Skip to content

Multipoint/VendorID hook (fake_l2c_fcr_chk_chan_modes) causes repeated A2DP/HFP disconnect cycling on Android 17 — everything else works fine without it #700

Description

@mahesh-yadav-DS

App version

v1.0.0-rc1 (FOSS release)

App source

GitHub

Device

Motorola Edge 30 Fusion

Android / OS version

Android 17 (SDK 37), Evolution X (custom ROM)

Root / hook method

Other (describe in additional context)

AirPods model

AirPods Pro 3

AirPods firmware

9442210

What happened

Root: Folkpatch(Apatch fork) + Xposed

Everything LibrePods offers outside of the VendorID/"act as Apple" hook (multi-device connectivity, transparency mode customization, hearing aid setup) works correctly on this device via the systemized priv-app permissions alone — battery status, ear detection, controls, metadata, etc. all function with a fully stable connection.

The problem is isolated specifically to the hook: with it active (either unconditionally via the systemized install, or via "act as Apple" through LSPosed), AirPods connect successfully but then enter a rapid disconnect/reconnect cycle within seconds — multiple A2DP/HEADSET STATE_DISCONNECTED events fire within a 5-second window, repeating continuously. This happens regardless of an iPhone being nearby (tested with the iPhone's Bluetooth fully off, ruling out Apple's cross-device auto-switching as the cause).

With the hook disabled (LibrePods either fully disabled, or LSPosed-enabled with "act as Apple" off), the connection is fully stable — no drops after 10-15+ minutes of normal use, versus consistent disconnects within 2-3 minutes with the hook active.

Root cause, as far as I could trace it: per your own docs and issue tracker, the underlying Android Bluetooth stack L2CAP channel-mode bug that fake_l2c_fcr_chk_chan_modes works around (needed for multipoint/VendorID features) has been confirmed fixed in Android 17. On this device (genuinely running Android 17 / SDK 37), the hook still unconditionally forces l2c_fcr_chk_chan_modes to return 1/true, which appears to conflict with the platform's now-correct native negotiation rather than filling a gap — producing the disconnect cycling.

I decompiled the release APK to check for a way to disable just this hook:

KotlinModule.onPackageLoaded (the Xposed/LSPosed-loaded path) reads getRemotePreferences("me.kavishdevar.librepods").getBoolean("vendor_id_hook", false) and calls NativeBridge.setSdpHook(value) accordingly — so this path is gated by a preference.
However, when LibrePods is installed as a systemized priv-app without being separately enabled as an LSPosed module, the same native hook still fires (confirmed via LibrePodsHook: fake_l2c_fcr_chk_chan_modes called in logcat), independent of the vendor_id_hook preference (which wasn't even present in settings.xml at the time). The systemized/Magisk-module install path appears to apply the hook unconditionally, with no way to opt out short of disabling the whole module.
Enabling LibrePods as an LSPosed module and turning on "act as Apple" (vendor_id_hook = true) reproduces the same disconnect cycling as the systemized-only install — confirming both paths route through the same setSdpHook call.
Turning "act as Apple" off (module still LSPosed-enabled, hook not invoked) is stable, matching the fully-disabled case.

Secondary, separate issue: with "act as Apple"/vendor_id_hook enabled, a second distinct error appears independent of the disconnect cycling, surfacing in-app as a "couldn't connect to socket" toast:

BluetoothSocketManager: Error creating bluetooth socket with constructor 3
java.lang.NoSuchMethodException: Cannot find matching constructor
at org.lsposed.hiddenapibypass.HiddenApiBypass.newInstance
at com.android.bluetooth.bthelper.utils.BluetoothSocketManager.createBluetoothSocket
at com.android.bluetooth.bthelper.pods.PodsService$connectToA2dpProfile$1$onServiceConnected$1.invokeSuspend

This looks like a separate Android-17-specific hidden API signature mismatch in the reflection-based BluetoothSocket construction used for the AACP command channel, unrelated to the L2CAP hook itself.

Suggested fix: would it be possible to have the systemized/Magisk-module install path also respect the vendor_id_hook preference (or a build-time Android-version check) so the hook can be conditionally skipped on Android 17+, similar to how the LSPosed path already works? Right now, since the hook applies unconditionally in the systemized install, the only way to get a stable connection is to disable LibrePods (or its LSPosed scope) entirely — losing every feature, including all the ones that work perfectly without the hook, rather than just losing multipoint/VendorID-specific functionality as would be expected.

Logs

librepods_bug_report_logs.txt

Additional context

Filing this per the request in #487 to report success/failure with build numbers on the L2CAP fix. Also possibly related to #246 (similar disconnect-while-active symptom reported on AirPods Pro 2 with APatch/KernelSU).

Metadata

Metadata

Assignees

No one assigned

    Labels

    androidAndroid app related issuesbugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions