⚠️ Beta. This build requires LSPosed 2.x — a framework implementing libxposed API 101. DuckUSB is now a modern Xposed module: it carries noxposedmodulemeta-data, so an older LSPosed does not reject it, it never lists it as a module at all. Nothing crashes and nothing bootloops; the app installs, opens, and reports "Not active" forever. On an older framework, stay on 1.3.3.
⚠️ Your settings reset to defaults. Module settings moved into the framework's remote preferences, and a modern module gets no world-readable-prefs redirect, so the 1.3.x values cannot be read. Re-check your toggles after updating. Your LSPosed scope is preserved.
Migrated to the modern Xposed API (libxposed 101). META-INF/xposed/ descriptors replace the manifest meta-data and assets/ entry points; XposedModule with onSystemServerStarting / onPackageReady replaces handleLoadPackage, so system_server is stated by the framework instead of inferred from a package name; interceptors replace XC_MethodHook; remote preferences replace XSharedPreferences. The UI can finally read its own LSPosed scope, and tells you when it is empty.
Framework mode is the stealthier mode, measurably. Inline hooks dirty code pages via copy-on-write, and a detector reading its own /proc/self/smaps sees them. Framework mode installs nothing inside the target, so there is nothing to find. Measured against Duck Detector: per-app leaves 4 kB dirty in libc.so, 28 kB in libart.so and 4 kB in linker64, and its Memory verdict is [DANGER] with 10 high-risk signals. Framework mode leaves none of it, and its Memory verdict is [CLEAR] — while the app still reads adb_enabled as 0. Per-app remains the only mode that also spoofs sys.usb.*; it just pays for that in the target's memory.
Two switches became one Method choice. Framework and per-app were always mutually exclusive, and as switches they could reach a state where framework mode was greyed out with nothing saying what to turn off first — the confusion behind #4. Picking one is now turning the other off.
Honest reporting. "Reboot needed" and "Nothing is spoofing" are distinct states instead of a green "Active". The readings card no longer tick-marks values — DuckUSB never spoofs itself, so that card is the real device state, not a pass/fail. The pause switch is captioned, because it stops hook bodies and is not the module's off switch. A manual "Check for updates" row was added; it only runs when tapped, and it refuses to offer a build your framework cannot load.
persist.sys.usb.config is still deliberately not spoofed: spoofing it makes reflection and libc disagree with getprop, and a detector reads that divergence as evidence of hooking. Truthful is quieter than inconsistent.
Verified on OP15 (Android 16, LSPosed 7846 / API 102) and OP11 (Android 16, LSPosed 7732 / API 101).
Source, issues and builds: https://github.com/Bouteillepleine/DuckUSB