diff --git a/api/src/main/java/io/github/libxposed/api/XposedContextWrapper.java b/api/src/main/java/io/github/libxposed/api/XposedContextWrapper.java index 9edb701..d4cb5fc 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedContextWrapper.java +++ b/api/src/main/java/io/github/libxposed/api/XposedContextWrapper.java @@ -87,25 +87,7 @@ public class XposedContextWrapper extends ContextWrapper implements XposedInterf */ @NonNull @Override - public final MethodUnhooker, Method> hookBefore(@NonNull Method origin, @NonNull BeforeHooker hooker) { - return getBaseContext().hookBefore(origin, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker, Method> hookAfter(@NonNull Method origin, @NonNull AfterHooker hooker) { - return getBaseContext().hookAfter(origin, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker, Method> hook(@NonNull Method origin, @NonNull Hooker hooker) { + public final MethodUnhooker hook(@NonNull Method origin, @NonNull Class hooker) { return getBaseContext().hook(origin, hooker); } @@ -114,25 +96,7 @@ public class XposedContextWrapper extends ContextWrapper implements XposedInterf */ @NonNull @Override - public final MethodUnhooker, Method> hookBefore(@NonNull Method origin, int priority, @NonNull BeforeHooker hooker) { - return getBaseContext().hookBefore(origin, priority, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker, Method> hookAfter(@NonNull Method origin, int priority, @NonNull AfterHooker hooker) { - return getBaseContext().hookAfter(origin, priority, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker, Method> hook(@NonNull Method origin, int priority, @NonNull Hooker hooker) { + public final MethodUnhooker hook(@NonNull Method origin, int priority, @NonNull Class hooker) { return getBaseContext().hook(origin, priority, hooker); } @@ -141,25 +105,7 @@ public class XposedContextWrapper extends ContextWrapper implements XposedInterf */ @NonNull @Override - public final MethodUnhooker>, Constructor> hookBefore(@NonNull Constructor origin, @NonNull BeforeHooker> hooker) { - return getBaseContext().hookBefore(origin, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker>, Constructor> hookAfter(@NonNull Constructor origin, @NonNull AfterHooker> hooker) { - return getBaseContext().hookAfter(origin, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker>, Constructor> hook(@NonNull Constructor origin, @NonNull Hooker> hooker) { + public final MethodUnhooker> hook(@NonNull Constructor origin, @NonNull Class hooker) { return getBaseContext().hook(origin, hooker); } @@ -168,25 +114,7 @@ public class XposedContextWrapper extends ContextWrapper implements XposedInterf */ @NonNull @Override - public final MethodUnhooker>, Constructor> hookBefore(@NonNull Constructor origin, int priority, @NonNull BeforeHooker> hooker) { - return getBaseContext().hookBefore(origin, priority, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker>, Constructor> hookAfter(@NonNull Constructor origin, int priority, @NonNull AfterHooker> hooker) { - return getBaseContext().hookAfter(origin, priority, hooker); - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public final MethodUnhooker>, Constructor> hook(@NonNull Constructor origin, int priority, @NonNull Hooker> hooker) { + public final MethodUnhooker> hook(@NonNull Constructor origin, int priority, @NonNull Class hooker) { return getBaseContext().hook(origin, priority, hooker); } diff --git a/api/src/main/java/io/github/libxposed/api/XposedInterface.java b/api/src/main/java/io/github/libxposed/api/XposedInterface.java index 8422dcc..67d2aa6 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedInterface.java +++ b/api/src/main/java/io/github/libxposed/api/XposedInterface.java @@ -13,10 +13,13 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Member; import java.lang.reflect.Method; import java.nio.ByteBuffer; -import java.util.ConcurrentModificationException; +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.utils.DexParser; @@ -62,239 +65,70 @@ public interface XposedInterface { int PRIORITY_HIGHEST = 10000; /** - * The interface Before hook callback. + * Interface for method / constructor hooking. Xposed modules should define their own hooker class + * and implement this interface. Normally, there could be one global hooker class for all method + * hooking. * - * @param the type parameter + *

+ * Classes implementing this interface should be annotated with {@link XposedHooker} and should provide + * two public static methods that are annotated with {@link BeforeInvocation} and {@link AfterInvocation}, + * respectively. + *

+ * + *

+ * The before invocation method should have the following signature:
+ * params: {@code member} - The {@link Member} object representing the method or constructor being hooked
+ *              + * {@code thisObject} - The {@code this} pointer, or null if the method is static
+ *              + * {@code args} - The arguments used for the method call
+ * returns: An {@link Hooker} object, used to save contextual information for current invocation routine + *

+ * + *

+ * The after invocation method should have the following signature:
+ * params: {@code extras} - The {@link Hooker} object returned by the before invocation method
+ *              + * {@code result} - The result of the invocation + *

+ * + *

Example usage:

+ * + *
{@code
+     *   @XposedHooker
+     *   public class ExampleHooker implements XposedInterface.Hooker {
+     *
+     *       @BeforeInvocation
+     *       public static @Nullable XposedInterface.Hooker
+     *       before(@NonNull Member member, @Nullable Object thisObject, @NonNull Object[] args) {
+     *           // Pre-hooking logic goes here
+     *       }
+     *
+     *       @AfterInvocation
+     *       public static void
+     *       after(@Nullable XposedInterface.Hooker extras, @Nullable Object result) {
+     *           // Post-hooking logic goes here
+     *       }
+     *   }
+     * }
*/ - interface BeforeHookCallback { + interface Hooker { + } + + /** + * Interface for canceling a hook. + * + * @param {@link Method} or {@link Constructor} + */ + interface MethodUnhooker { /** - * Gets origin. - * - * @return the origin + * Gets the method or constructor being hooked. */ @NonNull T getOrigin(); /** - * Gets this. - * - * @return the this - */ - @Nullable - Object getThis(); - - /** - * Get args object [ ]. - * - * @return the object [ ] - */ - @NonNull - Object[] getArgs(); - - /** - * Gets arg. - * - * @param the type parameter - * @param index the index - * @return the arg - */ - @Nullable - U getArg(int index); - - /** - * Sets arg. - * - * @param the type parameter - * @param index the index - * @param value the value - */ - void setArg(int index, U value); - - /** - * Return and skip. - * - * @param returnValue the return value - */ - void returnAndSkip(@Nullable Object returnValue); - - /** - * Throw and skip. - * - * @param throwable the throwable - */ - void throwAndSkip(@Nullable Throwable throwable); - - /** - * Invoke origin object. - * - * @return the object - * @throws InvocationTargetException the invocation target exception - * @throws IllegalArgumentException the illegal argument exception - * @throws IllegalAccessException the illegal access exception - */ - @Nullable - Object invokeOrigin() throws InvocationTargetException, IllegalArgumentException, IllegalAccessException; - - /** - * Sets extra. - * - * @param the type parameter - * @param key the key - * @param value the value - * @throws ConcurrentModificationException the concurrent modification exception - */ - void setExtra(@NonNull String key, @Nullable U value) throws ConcurrentModificationException; - } - - /** - * The interface After hook callback. - * - * @param the type parameter - */ - interface AfterHookCallback { - /** - * Gets origin. - * - * @return the origin - */ - @NonNull - T getOrigin(); - - /** - * Gets this. - * - * @return the this - */ - @Nullable - Object getThis(); - - /** - * Get args object [ ]. - * - * @return the object [ ] - */ - @NonNull - Object[] getArgs(); - - /** - * Gets result. - * - * @return the result - */ - @Nullable - Object getResult(); - - /** - * Gets throwable. - * - * @return the throwable - */ - @Nullable - Throwable getThrowable(); - - /** - * Is skipped boolean. - * - * @return the boolean - */ - boolean isSkipped(); - - /** - * Sets result. - * - * @param result the result - */ - void setResult(@Nullable Object result); - - /** - * Sets throwable. - * - * @param throwable the throwable - */ - void setThrowable(@Nullable Throwable throwable); - - /** - * Invoke origin object. - * - * @return the object - * @throws InvocationTargetException the invocation target exception - * @throws IllegalAccessException the illegal access exception - */ - @Nullable - Object invokeOrigin() throws InvocationTargetException, IllegalAccessException; - - /** - * Gets extra. - * - * @param the type parameter - * @param key the key - * @return the extra - */ - @Nullable - U getExtra(@NonNull String key); - } - - /** - * The interface Before hooker. - * - * @param the type parameter - */ - interface BeforeHooker { - /** - * Before. - * - * @param callback the callback - */ - void before(@NonNull BeforeHookCallback callback); - } - - /** - * The interface After hooker. - * - * @param the type parameter - */ - interface AfterHooker { - /** - * After. - * - * @param callback the callback - */ - void after(@NonNull AfterHookCallback callback); - } - - /** - * The interface Hooker. - * - * @param the type parameter - */ - interface Hooker extends BeforeHooker, AfterHooker { - } - - /** - * The interface Method unhooker. - * - * @param the type parameter - * @param the type parameter - */ - interface MethodUnhooker { - /** - * Gets origin. - * - * @return the origin - */ - @NonNull - U getOrigin(); - - /** - * Gets hooker. - * - * @return the hooker - */ - @NonNull - T getHooker(); - - /** - * Unhook. + * Cancels the hook. The behavior of calling this method multiple times is undefined. */ void unhook(); } @@ -329,30 +163,6 @@ public interface XposedInterface { */ int getFrameworkPrivilege(); - /** - * Hook before method unhooker. - * - * @param origin the origin - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - MethodUnhooker, Method> hookBefore(@NonNull Method origin, @NonNull BeforeHooker hooker); - - /** - * Hook after method unhooker. - * - * @param origin the origin - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - MethodUnhooker, Method> hookAfter(@NonNull Method origin, @NonNull AfterHooker hooker); - /** * Hook method unhooker. * @@ -363,33 +173,7 @@ public interface XposedInterface { * @throws HookFailedError if hook fails due to framework internal error */ @NonNull - MethodUnhooker, Method> hook(@NonNull Method origin, @NonNull Hooker hooker); - - /** - * Hook before method unhooker. - * - * @param origin the origin - * @param priority the priority - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - MethodUnhooker, Method> hookBefore(@NonNull Method origin, int priority, @NonNull BeforeHooker hooker); - - /** - * Hook after method unhooker. - * - * @param origin the origin - * @param priority the priority - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - MethodUnhooker, Method> hookAfter(@NonNull Method origin, int priority, @NonNull AfterHooker hooker); + MethodUnhooker hook(@NonNull Method origin, @NonNull Class hooker); /** * Hook method unhooker. @@ -402,33 +186,7 @@ public interface XposedInterface { * @throws HookFailedError if hook fails due to framework internal error */ @NonNull - MethodUnhooker, Method> hook(@NonNull Method origin, int priority, @NonNull Hooker hooker); - - /** - * Hook before method unhooker. - * - * @param the type parameter - * @param origin the origin - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - MethodUnhooker>, Constructor> hookBefore(@NonNull Constructor origin, @NonNull BeforeHooker> hooker); - - /** - * Hook after method unhooker. - * - * @param the type parameter - * @param origin the origin - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - MethodUnhooker>, Constructor> hookAfter(@NonNull Constructor origin, @NonNull AfterHooker> hooker); + MethodUnhooker hook(@NonNull Method origin, int priority, @NonNull Class hooker); /** * Hook method unhooker. @@ -441,35 +199,7 @@ public interface XposedInterface { * @throws HookFailedError if hook fails due to framework internal error */ @NonNull - MethodUnhooker>, Constructor> hook(@NonNull Constructor origin, @NonNull Hooker> hooker); - - /** - * Hook before method unhooker. - * - * @param the type parameter - * @param origin the origin - * @param priority the priority - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - MethodUnhooker>, Constructor> hookBefore(@NonNull Constructor origin, int priority, @NonNull BeforeHooker> hooker); - - /** - * Hook after method unhooker. - * - * @param the type parameter - * @param origin the origin - * @param priority the priority - * @param hooker the hooker - * @return the method unhooker - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke} - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - MethodUnhooker>, Constructor> hookAfter(@NonNull Constructor origin, int priority, @NonNull AfterHooker> hooker); + MethodUnhooker> hook(@NonNull Constructor origin, @NonNull Class hooker); /** * Hook method unhooker. @@ -483,7 +213,7 @@ public interface XposedInterface { * @throws HookFailedError if hook fails due to framework internal error */ @NonNull - MethodUnhooker>, Constructor> hook(@NonNull Constructor origin, int priority, @NonNull Hooker> hooker); + MethodUnhooker> hook(@NonNull Constructor origin, int priority, @NonNull Class hooker); /** * Deoptimizes a method in case hooked callee is not called because of inline. diff --git a/api/src/main/java/io/github/libxposed/api/annotations/AfterInvocation.java b/api/src/main/java/io/github/libxposed/api/annotations/AfterInvocation.java new file mode 100644 index 0000000..e26b318 --- /dev/null +++ b/api/src/main/java/io/github/libxposed/api/annotations/AfterInvocation.java @@ -0,0 +1,11 @@ +package io.github.libxposed.api.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface AfterInvocation { +} diff --git a/api/src/main/java/io/github/libxposed/api/annotations/BeforeInvocation.java b/api/src/main/java/io/github/libxposed/api/annotations/BeforeInvocation.java new file mode 100644 index 0000000..7b4a17b --- /dev/null +++ b/api/src/main/java/io/github/libxposed/api/annotations/BeforeInvocation.java @@ -0,0 +1,11 @@ +package io.github.libxposed.api.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface BeforeInvocation { +} diff --git a/api/src/main/java/io/github/libxposed/api/annotations/XposedHooker.java b/api/src/main/java/io/github/libxposed/api/annotations/XposedHooker.java new file mode 100644 index 0000000..809a5a7 --- /dev/null +++ b/api/src/main/java/io/github/libxposed/api/annotations/XposedHooker.java @@ -0,0 +1,11 @@ +package io.github.libxposed.api.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface XposedHooker { +}