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 <krc440002@gmail.com>
This commit is contained in:
parent
ea71745430
commit
cdc536f10b
|
|
@ -22,9 +22,12 @@
|
||||||
-keepclassmembers class org.lsposed.lspd.impl.LSPosedHookCallback {
|
-keepclassmembers class org.lsposed.lspd.impl.LSPosedHookCallback {
|
||||||
public <methods>;
|
public <methods>;
|
||||||
}
|
}
|
||||||
-keep,allowoptimization,allowobfuscation @io.github.libxposed.api.annotations.* class * {
|
-keepclassmembers,allowoptimization class ** implements io.github.libxposed.api.XposedInterface$Hooker {
|
||||||
@io.github.libxposed.api.annotations.BeforeInvocation <methods>;
|
public static *** before();
|
||||||
@io.github.libxposed.api.annotations.AfterInvocation <methods>;
|
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 {
|
-assumenosideeffects class android.util.Log {
|
||||||
public static *** v(...);
|
public static *** v(...);
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,10 @@ import android.app.ActivityThread;
|
||||||
|
|
||||||
import de.robv.android.xposed.XposedInit;
|
import de.robv.android.xposed.XposedInit;
|
||||||
import io.github.libxposed.api.XposedInterface;
|
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 {
|
public class AttachHooker implements XposedInterface.Hooker {
|
||||||
|
|
||||||
@AfterInvocation
|
public static void after(XposedInterface.AfterHookCallback callback) {
|
||||||
public static void afterHookedMethod(XposedInterface.AfterHookCallback callback) {
|
|
||||||
XposedInit.loadModules((ActivityThread) callback.getThisObject());
|
XposedInit.loadModules((ActivityThread) callback.getThisObject());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,10 @@ import org.lsposed.lspd.impl.LSPosedBridge;
|
||||||
import org.lsposed.lspd.util.Utils.Log;
|
import org.lsposed.lspd.util.Utils.Log;
|
||||||
|
|
||||||
import io.github.libxposed.api.XposedInterface;
|
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 {
|
public class CrashDumpHooker implements XposedInterface.Hooker {
|
||||||
|
|
||||||
@BeforeInvocation
|
public static void before(XposedInterface.BeforeHookCallback callback) {
|
||||||
public static void beforeHookedMethod(XposedInterface.BeforeHookCallback callback) {
|
|
||||||
try {
|
try {
|
||||||
var e = (Throwable) callback.getArgs()[0];
|
var e = (Throwable) callback.getArgs()[0];
|
||||||
LSPosedBridge.log("Crash unexpectedly: " + Log.getStackTraceString(e));
|
LSPosedBridge.log("Crash unexpectedly: " + Log.getStackTraceString(e));
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,8 @@ import org.lsposed.lspd.impl.LSPosedHelper;
|
||||||
import org.lsposed.lspd.util.Hookers;
|
import org.lsposed.lspd.util.Hookers;
|
||||||
|
|
||||||
import io.github.libxposed.api.XposedInterface;
|
import io.github.libxposed.api.XposedInterface;
|
||||||
import io.github.libxposed.api.annotations.AfterInvocation;
|
|
||||||
import io.github.libxposed.api.annotations.XposedHooker;
|
|
||||||
|
|
||||||
// system_server initialization
|
// system_server initialization
|
||||||
@XposedHooker
|
|
||||||
public class HandleSystemServerProcessHooker implements XposedInterface.Hooker {
|
public class HandleSystemServerProcessHooker implements XposedInterface.Hooker {
|
||||||
|
|
||||||
public interface Callback {
|
public interface Callback {
|
||||||
|
|
@ -42,8 +39,7 @@ public class HandleSystemServerProcessHooker implements XposedInterface.Hooker {
|
||||||
public static volatile Callback callback = null;
|
public static volatile Callback callback = null;
|
||||||
|
|
||||||
@SuppressLint("PrivateApi")
|
@SuppressLint("PrivateApi")
|
||||||
@AfterInvocation
|
public static void after() {
|
||||||
public static void afterHookedMethod() {
|
|
||||||
Hookers.logD("ZygoteInit#handleSystemServerProcess() starts");
|
Hookers.logD("ZygoteInit#handleSystemServerProcess() starts");
|
||||||
try {
|
try {
|
||||||
// get system_server classLoader
|
// get system_server classLoader
|
||||||
|
|
|
||||||
|
|
@ -51,11 +51,8 @@ import de.robv.android.xposed.XposedInit;
|
||||||
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
||||||
import io.github.libxposed.api.XposedInterface;
|
import io.github.libxposed.api.XposedInterface;
|
||||||
import io.github.libxposed.api.XposedModuleInterface;
|
import io.github.libxposed.api.XposedModuleInterface;
|
||||||
import io.github.libxposed.api.annotations.AfterInvocation;
|
|
||||||
import io.github.libxposed.api.annotations.XposedHooker;
|
|
||||||
|
|
||||||
@SuppressLint("BlockedPrivateApi")
|
@SuppressLint("BlockedPrivateApi")
|
||||||
@XposedHooker
|
|
||||||
public class LoadedApkCreateCLHooker implements XposedInterface.Hooker {
|
public class LoadedApkCreateCLHooker implements XposedInterface.Hooker {
|
||||||
private final static Field defaultClassLoaderField;
|
private final static Field defaultClassLoaderField;
|
||||||
|
|
||||||
|
|
@ -77,8 +74,7 @@ public class LoadedApkCreateCLHooker implements XposedInterface.Hooker {
|
||||||
loadedApks.add(loadedApk);
|
loadedApks.add(loadedApk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterInvocation
|
public static void after(XposedInterface.AfterHookCallback callback) {
|
||||||
public static void afterHookedMethod(XposedInterface.AfterHookCallback callback) {
|
|
||||||
LoadedApk loadedApk = (LoadedApk) callback.getThisObject();
|
LoadedApk loadedApk = (LoadedApk) callback.getThisObject();
|
||||||
|
|
||||||
if (callback.getArgs()[0] != null || !loadedApks.contains(loadedApk)) {
|
if (callback.getArgs()[0] != null || !loadedApks.contains(loadedApk)) {
|
||||||
|
|
|
||||||
|
|
@ -29,15 +29,11 @@ import org.lsposed.lspd.util.Utils.Log;
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
import de.robv.android.xposed.XposedHelpers;
|
||||||
import de.robv.android.xposed.XposedInit;
|
import de.robv.android.xposed.XposedInit;
|
||||||
import io.github.libxposed.api.XposedInterface;
|
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
|
// when a package is loaded for an existing process, trigger the callbacks as well
|
||||||
@XposedHooker
|
|
||||||
public class LoadedApkCtorHooker implements XposedInterface.Hooker {
|
public class LoadedApkCtorHooker implements XposedInterface.Hooker {
|
||||||
|
|
||||||
@AfterInvocation
|
public static void after(XposedInterface.AfterHookCallback callback) {
|
||||||
public static void afterHookedMethod(XposedInterface.AfterHookCallback callback) {
|
|
||||||
Hookers.logD("LoadedApk#<init> starts");
|
Hookers.logD("LoadedApk#<init> starts");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,10 @@ import org.lsposed.lspd.impl.LSPosedBridge;
|
||||||
import org.lsposed.lspd.nativebridge.HookBridge;
|
import org.lsposed.lspd.nativebridge.HookBridge;
|
||||||
|
|
||||||
import io.github.libxposed.api.XposedInterface;
|
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 {
|
public class OpenDexFileHooker implements XposedInterface.Hooker {
|
||||||
|
|
||||||
@AfterInvocation
|
public static void after(XposedInterface.AfterHookCallback callback) {
|
||||||
public static void afterHookedMethod(XposedInterface.AfterHookCallback callback) {
|
|
||||||
ClassLoader classLoader = null;
|
ClassLoader classLoader = null;
|
||||||
for (var arg : callback.getArgs()) {
|
for (var arg : callback.getArgs()) {
|
||||||
if (arg instanceof ClassLoader) {
|
if (arg instanceof ClassLoader) {
|
||||||
|
|
|
||||||
|
|
@ -32,14 +32,10 @@ import de.robv.android.xposed.XposedInit;
|
||||||
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
||||||
import io.github.libxposed.api.XposedInterface;
|
import io.github.libxposed.api.XposedInterface;
|
||||||
import io.github.libxposed.api.XposedModuleInterface;
|
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 {
|
public class StartBootstrapServicesHooker implements XposedInterface.Hooker {
|
||||||
|
|
||||||
@BeforeInvocation
|
public static void before() {
|
||||||
public static void beforeHookedMethod() {
|
|
||||||
logD("SystemServer#startBootstrapServices() starts");
|
logD("SystemServer#startBootstrapServices() starts");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,6 @@ import java.lang.reflect.Modifier;
|
||||||
|
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import de.robv.android.xposed.XposedBridge;
|
||||||
import io.github.libxposed.api.XposedInterface;
|
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;
|
import io.github.libxposed.api.errors.HookFailedError;
|
||||||
|
|
||||||
public class LSPosedBridge {
|
public class LSPosedBridge {
|
||||||
|
|
@ -218,16 +215,14 @@ public class LSPosedBridge {
|
||||||
throw new IllegalArgumentException("Cannot hook Method.invoke");
|
throw new IllegalArgumentException("Cannot hook Method.invoke");
|
||||||
} else if (hooker == null) {
|
} else if (hooker == null) {
|
||||||
throw new IllegalArgumentException("hooker should not be 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;
|
Method beforeInvocation = null, afterInvocation = null;
|
||||||
var modifiers = Modifier.PUBLIC | Modifier.STATIC;
|
var modifiers = Modifier.PUBLIC | Modifier.STATIC;
|
||||||
for (var method : hooker.getDeclaredMethods()) {
|
for (var method : hooker.getDeclaredMethods()) {
|
||||||
if (method.getAnnotation(BeforeInvocation.class) != null) {
|
if (method.getName().equals("before")) {
|
||||||
if (beforeInvocation != null) {
|
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;
|
boolean valid = (method.getModifiers() & modifiers) == modifiers;
|
||||||
var params = method.getParameterTypes();
|
var params = method.getParameterTypes();
|
||||||
|
|
@ -237,13 +232,12 @@ public class LSPosedBridge {
|
||||||
valid = false;
|
valid = false;
|
||||||
}
|
}
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
throw new IllegalArgumentException("BeforeInvocation method format is invalid");
|
throw new IllegalArgumentException("before method format is invalid");
|
||||||
}
|
}
|
||||||
beforeInvocation = method;
|
beforeInvocation = method;
|
||||||
}
|
} else if (method.getName().equals("after")) {
|
||||||
if (method.getAnnotation(AfterInvocation.class) != null) {
|
|
||||||
if (afterInvocation != null) {
|
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;
|
boolean valid = (method.getModifiers() & modifiers) == modifiers;
|
||||||
valid &= method.getReturnType().equals(void.class);
|
valid &= method.getReturnType().equals(void.class);
|
||||||
|
|
@ -254,13 +248,13 @@ public class LSPosedBridge {
|
||||||
valid = false;
|
valid = false;
|
||||||
}
|
}
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
throw new IllegalArgumentException("AfterInvocation method format is invalid");
|
throw new IllegalArgumentException("after method format is invalid");
|
||||||
}
|
}
|
||||||
afterInvocation = method;
|
afterInvocation = method;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (beforeInvocation == null && afterInvocation == null) {
|
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 {
|
try {
|
||||||
if (beforeInvocation == null) {
|
if (beforeInvocation == null) {
|
||||||
|
|
@ -271,7 +265,7 @@ public class LSPosedBridge {
|
||||||
var ret = beforeInvocation.getReturnType();
|
var ret = beforeInvocation.getReturnType();
|
||||||
var params = afterInvocation.getParameterTypes();
|
var params = afterInvocation.getParameterTypes();
|
||||||
if (ret != void.class && params.length == 2 && !ret.equals(params[1])) {
|
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) {
|
} catch (NoSuchMethodException e) {
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,6 @@ import org.lsposed.lspd.service.BridgeService;
|
||||||
import org.lsposed.lspd.util.Utils;
|
import org.lsposed.lspd.util.Utils;
|
||||||
|
|
||||||
import io.github.libxposed.api.XposedInterface;
|
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 {
|
public class ParasiticManagerSystemHooker implements HandleSystemServerProcessHooker.Callback {
|
||||||
|
|
@ -33,10 +31,8 @@ public class ParasiticManagerSystemHooker implements HandleSystemServerProcessHo
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
@XposedHooker
|
|
||||||
private static class Hooker implements XposedInterface.Hooker {
|
private static class Hooker implements XposedInterface.Hooker {
|
||||||
@AfterInvocation
|
public static void after(XposedInterface.AfterHookCallback callback) throws Throwable {
|
||||||
public static void afterHookedMethod(XposedInterface.AfterHookCallback callback) throws Throwable {
|
|
||||||
var intent = (Intent) callback.getArgs()[0];
|
var intent = (Intent) callback.getArgs()[0];
|
||||||
if (intent == null) return;
|
if (intent == null) return;
|
||||||
if (!intent.hasCategory("org.lsposed.manager.LAUNCH_MANAGER")) return;
|
if (!intent.hasCategory("org.lsposed.manager.LAUNCH_MANAGER")) return;
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 55efdf9d159195261d7326e9e125965a90025a12
|
Subproject commit 64e29bd657ef4d2540b34402f5a988778f29e676
|
||||||
Loading…
Reference in New Issue