From cdc536f10b3385889a24e1e14f177df86741e5f6 Mon Sep 17 00:00:00 2001 From: JingMatrix Date: Fri, 13 Feb 2026 18:27:16 +0100 Subject: [PATCH] Adapt LSPosedBridge to convention-based hooker discovery (#534) We update `LSPosedBridge` to align with upstream API changes, which have replaced annotation-based hooker discovery with a naming convention. The `doHook` implementation has been refactored to: - Remove dependencies on the deleted `io.github.libxposed.api.annotations` package (`XposedHooker`, `BeforeInvocation`, `AfterInvocation`). - Scan for public static methods explicitly named `before` and `after` instead of relying on annotations. - Enforce validation on these named methods to ensure they match the required signatures. To adapt to this change, existing Hooker classes are refactored by removing the deprecated annotations and renaming their callback methods to `before` and `after` respectively. Co-authored-by: frknkrc44 --- core/proguard-rules.pro | 9 +++++--- .../org/lsposed/lspd/hooker/AttachHooker.java | 6 +---- .../lsposed/lspd/hooker/CrashDumpHooker.java | 6 +---- .../HandleSystemServerProcessHooker.java | 6 +---- .../lspd/hooker/LoadedApkCreateCLHooker.java | 6 +---- .../lspd/hooker/LoadedApkCtorHooker.java | 6 +---- .../lspd/hooker/OpenDexFileHooker.java | 6 +---- .../hooker/StartBootstrapServicesHooker.java | 6 +---- .../org/lsposed/lspd/impl/LSPosedBridge.java | 22 +++++++------------ .../util/ParasiticManagerSystemHooker.java | 6 +---- xposed/libxposed | 2 +- 11 files changed, 23 insertions(+), 58 deletions(-) diff --git a/core/proguard-rules.pro b/core/proguard-rules.pro index 4638bb63..844704e3 100644 --- a/core/proguard-rules.pro +++ b/core/proguard-rules.pro @@ -22,9 +22,12 @@ -keepclassmembers class org.lsposed.lspd.impl.LSPosedHookCallback { public ; } --keep,allowoptimization,allowobfuscation @io.github.libxposed.api.annotations.* class * { - @io.github.libxposed.api.annotations.BeforeInvocation ; - @io.github.libxposed.api.annotations.AfterInvocation ; +-keepclassmembers,allowoptimization class ** implements io.github.libxposed.api.XposedInterface$Hooker { + public static *** before(); + public static *** before(io.github.libxposed.api.XposedInterface$BeforeHookCallback); + public static void after(); + public static void after(io.github.libxposed.api.XposedInterface$AfterHookCallback); + public static void after(io.github.libxposed.api.XposedInterface$AfterHookCallback, ***); } -assumenosideeffects class android.util.Log { public static *** v(...); diff --git a/core/src/main/java/org/lsposed/lspd/hooker/AttachHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/AttachHooker.java index b003ac2f..3e77ba15 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/AttachHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/AttachHooker.java @@ -4,14 +4,10 @@ import android.app.ActivityThread; import de.robv.android.xposed.XposedInit; import io.github.libxposed.api.XposedInterface; -import io.github.libxposed.api.annotations.AfterInvocation; -import io.github.libxposed.api.annotations.XposedHooker; -@XposedHooker public class AttachHooker implements XposedInterface.Hooker { - @AfterInvocation - public static void afterHookedMethod(XposedInterface.AfterHookCallback callback) { + public static void after(XposedInterface.AfterHookCallback callback) { XposedInit.loadModules((ActivityThread) callback.getThisObject()); } } diff --git a/core/src/main/java/org/lsposed/lspd/hooker/CrashDumpHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/CrashDumpHooker.java index ea94b132..53ab5c0c 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/CrashDumpHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/CrashDumpHooker.java @@ -4,14 +4,10 @@ import org.lsposed.lspd.impl.LSPosedBridge; import org.lsposed.lspd.util.Utils.Log; import io.github.libxposed.api.XposedInterface; -import io.github.libxposed.api.annotations.BeforeInvocation; -import io.github.libxposed.api.annotations.XposedHooker; -@XposedHooker public class CrashDumpHooker implements XposedInterface.Hooker { - @BeforeInvocation - public static void beforeHookedMethod(XposedInterface.BeforeHookCallback callback) { + public static void before(XposedInterface.BeforeHookCallback callback) { try { var e = (Throwable) callback.getArgs()[0]; LSPosedBridge.log("Crash unexpectedly: " + Log.getStackTraceString(e)); diff --git a/core/src/main/java/org/lsposed/lspd/hooker/HandleSystemServerProcessHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/HandleSystemServerProcessHooker.java index 4552153e..0a67995c 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/HandleSystemServerProcessHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/HandleSystemServerProcessHooker.java @@ -27,11 +27,8 @@ import org.lsposed.lspd.impl.LSPosedHelper; import org.lsposed.lspd.util.Hookers; import io.github.libxposed.api.XposedInterface; -import io.github.libxposed.api.annotations.AfterInvocation; -import io.github.libxposed.api.annotations.XposedHooker; // system_server initialization -@XposedHooker public class HandleSystemServerProcessHooker implements XposedInterface.Hooker { public interface Callback { @@ -42,8 +39,7 @@ public class HandleSystemServerProcessHooker implements XposedInterface.Hooker { public static volatile Callback callback = null; @SuppressLint("PrivateApi") - @AfterInvocation - public static void afterHookedMethod() { + public static void after() { Hookers.logD("ZygoteInit#handleSystemServerProcess() starts"); try { // get system_server classLoader diff --git a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCreateCLHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCreateCLHooker.java index 161c730e..b5c1bec0 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCreateCLHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCreateCLHooker.java @@ -51,11 +51,8 @@ import de.robv.android.xposed.XposedInit; import de.robv.android.xposed.callbacks.XC_LoadPackage; import io.github.libxposed.api.XposedInterface; import io.github.libxposed.api.XposedModuleInterface; -import io.github.libxposed.api.annotations.AfterInvocation; -import io.github.libxposed.api.annotations.XposedHooker; @SuppressLint("BlockedPrivateApi") -@XposedHooker public class LoadedApkCreateCLHooker implements XposedInterface.Hooker { private final static Field defaultClassLoaderField; @@ -77,8 +74,7 @@ public class LoadedApkCreateCLHooker implements XposedInterface.Hooker { loadedApks.add(loadedApk); } - @AfterInvocation - public static void afterHookedMethod(XposedInterface.AfterHookCallback callback) { + public static void after(XposedInterface.AfterHookCallback callback) { LoadedApk loadedApk = (LoadedApk) callback.getThisObject(); if (callback.getArgs()[0] != null || !loadedApks.contains(loadedApk)) { diff --git a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCtorHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCtorHooker.java index e84e3d1d..e0a4af96 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCtorHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCtorHooker.java @@ -29,15 +29,11 @@ import org.lsposed.lspd.util.Utils.Log; import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.XposedInit; import io.github.libxposed.api.XposedInterface; -import io.github.libxposed.api.annotations.AfterInvocation; -import io.github.libxposed.api.annotations.XposedHooker; // when a package is loaded for an existing process, trigger the callbacks as well -@XposedHooker public class LoadedApkCtorHooker implements XposedInterface.Hooker { - @AfterInvocation - public static void afterHookedMethod(XposedInterface.AfterHookCallback callback) { + public static void after(XposedInterface.AfterHookCallback callback) { Hookers.logD("LoadedApk# starts"); try { diff --git a/core/src/main/java/org/lsposed/lspd/hooker/OpenDexFileHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/OpenDexFileHooker.java index af6f70a2..acbef26d 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/OpenDexFileHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/OpenDexFileHooker.java @@ -6,14 +6,10 @@ import org.lsposed.lspd.impl.LSPosedBridge; import org.lsposed.lspd.nativebridge.HookBridge; import io.github.libxposed.api.XposedInterface; -import io.github.libxposed.api.annotations.AfterInvocation; -import io.github.libxposed.api.annotations.XposedHooker; -@XposedHooker public class OpenDexFileHooker implements XposedInterface.Hooker { - @AfterInvocation - public static void afterHookedMethod(XposedInterface.AfterHookCallback callback) { + public static void after(XposedInterface.AfterHookCallback callback) { ClassLoader classLoader = null; for (var arg : callback.getArgs()) { if (arg instanceof ClassLoader) { diff --git a/core/src/main/java/org/lsposed/lspd/hooker/StartBootstrapServicesHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/StartBootstrapServicesHooker.java index 30bf835d..3594095f 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/StartBootstrapServicesHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/StartBootstrapServicesHooker.java @@ -32,14 +32,10 @@ import de.robv.android.xposed.XposedInit; import de.robv.android.xposed.callbacks.XC_LoadPackage; import io.github.libxposed.api.XposedInterface; import io.github.libxposed.api.XposedModuleInterface; -import io.github.libxposed.api.annotations.BeforeInvocation; -import io.github.libxposed.api.annotations.XposedHooker; -@XposedHooker public class StartBootstrapServicesHooker implements XposedInterface.Hooker { - @BeforeInvocation - public static void beforeHookedMethod() { + public static void before() { logD("SystemServer#startBootstrapServices() starts"); try { diff --git a/core/src/main/java/org/lsposed/lspd/impl/LSPosedBridge.java b/core/src/main/java/org/lsposed/lspd/impl/LSPosedBridge.java index 27c7ce8c..8dd201dd 100644 --- a/core/src/main/java/org/lsposed/lspd/impl/LSPosedBridge.java +++ b/core/src/main/java/org/lsposed/lspd/impl/LSPosedBridge.java @@ -12,9 +12,6 @@ import java.lang.reflect.Modifier; import de.robv.android.xposed.XposedBridge; import io.github.libxposed.api.XposedInterface; -import io.github.libxposed.api.annotations.AfterInvocation; -import io.github.libxposed.api.annotations.BeforeInvocation; -import io.github.libxposed.api.annotations.XposedHooker; import io.github.libxposed.api.errors.HookFailedError; public class LSPosedBridge { @@ -218,16 +215,14 @@ public class LSPosedBridge { throw new IllegalArgumentException("Cannot hook Method.invoke"); } else if (hooker == null) { throw new IllegalArgumentException("hooker should not be null!"); - } else if (hooker.getAnnotation(XposedHooker.class) == null) { - throw new IllegalArgumentException("Hooker should be annotated with @XposedHooker"); } Method beforeInvocation = null, afterInvocation = null; var modifiers = Modifier.PUBLIC | Modifier.STATIC; for (var method : hooker.getDeclaredMethods()) { - if (method.getAnnotation(BeforeInvocation.class) != null) { + if (method.getName().equals("before")) { if (beforeInvocation != null) { - throw new IllegalArgumentException("More than one method annotated with @BeforeInvocation"); + throw new IllegalArgumentException("More than one method named before"); } boolean valid = (method.getModifiers() & modifiers) == modifiers; var params = method.getParameterTypes(); @@ -237,13 +232,12 @@ public class LSPosedBridge { valid = false; } if (!valid) { - throw new IllegalArgumentException("BeforeInvocation method format is invalid"); + throw new IllegalArgumentException("before method format is invalid"); } beforeInvocation = method; - } - if (method.getAnnotation(AfterInvocation.class) != null) { + } else if (method.getName().equals("after")) { if (afterInvocation != null) { - throw new IllegalArgumentException("More than one method annotated with @AfterInvocation"); + throw new IllegalArgumentException("More than one method named after"); } boolean valid = (method.getModifiers() & modifiers) == modifiers; valid &= method.getReturnType().equals(void.class); @@ -254,13 +248,13 @@ public class LSPosedBridge { valid = false; } if (!valid) { - throw new IllegalArgumentException("AfterInvocation method format is invalid"); + throw new IllegalArgumentException("after method format is invalid"); } afterInvocation = method; } } if (beforeInvocation == null && afterInvocation == null) { - throw new IllegalArgumentException("No method annotated with @BeforeInvocation or @AfterInvocation"); + throw new IllegalArgumentException("No method named before or after found in " + hooker.getName()); } try { if (beforeInvocation == null) { @@ -271,7 +265,7 @@ public class LSPosedBridge { var ret = beforeInvocation.getReturnType(); var params = afterInvocation.getParameterTypes(); if (ret != void.class && params.length == 2 && !ret.equals(params[1])) { - throw new IllegalArgumentException("BeforeInvocation and AfterInvocation method format is invalid"); + throw new IllegalArgumentException("before and after method format is invalid"); } } } catch (NoSuchMethodException e) { diff --git a/magisk-loader/src/main/java/org/lsposed/lspd/util/ParasiticManagerSystemHooker.java b/magisk-loader/src/main/java/org/lsposed/lspd/util/ParasiticManagerSystemHooker.java index 578627a8..1a203916 100644 --- a/magisk-loader/src/main/java/org/lsposed/lspd/util/ParasiticManagerSystemHooker.java +++ b/magisk-loader/src/main/java/org/lsposed/lspd/util/ParasiticManagerSystemHooker.java @@ -12,8 +12,6 @@ import org.lsposed.lspd.service.BridgeService; import org.lsposed.lspd.util.Utils; import io.github.libxposed.api.XposedInterface; -import io.github.libxposed.api.annotations.AfterInvocation; -import io.github.libxposed.api.annotations.XposedHooker; public class ParasiticManagerSystemHooker implements HandleSystemServerProcessHooker.Callback { @@ -33,10 +31,8 @@ public class ParasiticManagerSystemHooker implements HandleSystemServerProcessHo } }*/ - @XposedHooker private static class Hooker implements XposedInterface.Hooker { - @AfterInvocation - public static void afterHookedMethod(XposedInterface.AfterHookCallback callback) throws Throwable { + public static void after(XposedInterface.AfterHookCallback callback) throws Throwable { var intent = (Intent) callback.getArgs()[0]; if (intent == null) return; if (!intent.hasCategory("org.lsposed.manager.LAUNCH_MANAGER")) return; diff --git a/xposed/libxposed b/xposed/libxposed index 55efdf9d..64e29bd6 160000 --- a/xposed/libxposed +++ b/xposed/libxposed @@ -1 +1 @@ -Subproject commit 55efdf9d159195261d7326e9e125965a90025a12 +Subproject commit 64e29bd657ef4d2540b34402f5a988778f29e676