From 128ead6aab8861c73ae739719af669f373023e7a Mon Sep 17 00:00:00 2001 From: Nullptr Date: Mon, 28 Oct 2024 15:58:54 +0100 Subject: [PATCH 1/8] Update deps --- gradle/libs.versions.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 60cbcd5..2254578 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,8 +1,8 @@ [versions] -annotation = "1.8.0" -kotlin = "2.0.0" -lint = "31.5.1" -agp = "8.5.1" +annotation = "1.9.0" +kotlin = "2.0.21" +lint = "31.7.1" +agp = "8.7.1" [plugins] kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } From 7d83e02b3b739dc9178df0930d3f7cf1b197e6de Mon Sep 17 00:00:00 2001 From: Nullptr Date: Mon, 28 Oct 2024 16:04:49 +0100 Subject: [PATCH 2/8] Rename MethodUnhooker to HookHandle, add invoke method --- .../github/libxposed/api/XposedInterface.java | 49 +++++++++++-------- .../libxposed/api/XposedInterfaceWrapper.java | 12 ++--- 2 files changed, 35 insertions(+), 26 deletions(-) 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 3c4ac86..062a935 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedInterface.java +++ b/api/src/main/java/io/github/libxposed/api/XposedInterface.java @@ -211,17 +211,29 @@ interface Hooker { } /** - * Interface for canceling a hook. + * Handle for a hook. * * @param {@link Method} or {@link Constructor} */ - interface MethodUnhooker { + interface HookHandle { /** * Gets the method or constructor being hooked. */ @NonNull T getOrigin(); + /** + * Similar to {@link Method#invoke(Object, Object...)}, but skips Xposed hooks with lower priority. + * + * @param method The method or constructor to be called + * @param thisObject For non-static calls, the {@code this} pointer, otherwise {@code null} + * @param args The arguments used for the method call + * @return The result returned from the invoked method + * @see Method#invoke(Object, Object...) + */ + @Nullable + Object invoke(@NonNull T method, @Nullable Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException; + /** * Cancels the hook. The behavior of calling this method multiple times is undefined. */ @@ -263,13 +275,13 @@ interface MethodUnhooker { * * @param origin The method to be hooked * @param hooker The hooker class - * @return Unhooker for canceling the hook + * @return Handle for the hook * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke}, * or hooker is invalid * @throws HookFailedError if hook fails due to framework internal error */ @NonNull - MethodUnhooker hook(@NonNull Method origin, @NonNull Class hooker); + HookHandle hook(@NonNull Method origin, @NonNull Class hooker); /** * Hook the static initializer of a class with default priority. @@ -279,12 +291,12 @@ interface MethodUnhooker { * * @param origin The class to be hooked * @param hooker The hooker class - * @return Unhooker for canceling the hook + * @return Handle for the hook * @throws IllegalArgumentException if class has no static initializer or hooker is invalid * @throws HookFailedError if hook fails due to framework internal error */ @NonNull - MethodUnhooker> hookClassInitializer(@NonNull Class origin, @NonNull Class hooker); + HookHandle> hookClassInitializer(@NonNull Class origin, @NonNull Class hooker); /** * Hook the static initializer of a class with specified priority. @@ -295,12 +307,12 @@ interface MethodUnhooker { * @param origin The class to be hooked * @param priority The hook priority * @param hooker The hooker class - * @return Unhooker for canceling the hook + * @return Handle for the hook * @throws IllegalArgumentException if class has no static initializer or hooker is invalid * @throws HookFailedError if hook fails due to framework internal error */ @NonNull - MethodUnhooker> hookClassInitializer(@NonNull Class origin, int priority, @NonNull Class hooker); + HookHandle> hookClassInitializer(@NonNull Class origin, int priority, @NonNull Class hooker); /** * Hook a method with specified priority. @@ -308,13 +320,13 @@ interface MethodUnhooker { * @param origin The method to be hooked * @param priority The hook priority * @param hooker The hooker class - * @return Unhooker for canceling the hook + * @return Handle for the hook * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke}, * or hooker is invalid * @throws HookFailedError if hook fails due to framework internal error */ @NonNull - MethodUnhooker hook(@NonNull Method origin, int priority, @NonNull Class hooker); + HookHandle hook(@NonNull Method origin, int priority, @NonNull Class hooker); /** * Hook a constructor with default priority. @@ -322,13 +334,13 @@ interface MethodUnhooker { * @param The type of the constructor * @param origin The constructor to be hooked * @param hooker The hooker class - * @return Unhooker for canceling the hook + * @return Handle for the hook * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke}, * or hooker is invalid * @throws HookFailedError if hook fails due to framework internal error */ @NonNull - MethodUnhooker> hook(@NonNull Constructor origin, @NonNull Class hooker); + HookHandle> hook(@NonNull Constructor origin, @NonNull Class hooker); /** * Hook a constructor with specified priority. @@ -337,13 +349,13 @@ interface MethodUnhooker { * @param origin The constructor to be hooked * @param priority The hook priority * @param hooker The hooker class - * @return Unhooker for canceling the hook + * @return Handle for the hook * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke}, * or hooker is invalid * @throws HookFailedError if hook fails due to framework internal error */ @NonNull - MethodUnhooker> hook(@NonNull Constructor origin, int priority, @NonNull Class hooker); + HookHandle> hook(@NonNull Constructor origin, int priority, @NonNull Class hooker); /** * Deoptimizes a method in case hooked callee is not called because of inline. @@ -374,8 +386,7 @@ interface MethodUnhooker { boolean deoptimize(@NonNull Constructor constructor); /** - * Basically the same as {@link Method#invoke(Object, Object...)}, but calls the original method - * as it was before the interception by Xposed. + * Basically the same as {@link Method#invoke(Object, Object...)}, but skips all Xposed hooks. * * @param method The method to be called * @param thisObject For non-static calls, the {@code this} pointer, otherwise {@code null} @@ -387,8 +398,7 @@ interface MethodUnhooker { Object invokeOrigin(@NonNull Method method, @Nullable Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException; /** - * Basically the same as {@link Constructor#newInstance(Object...)}, but calls the original constructor - * as it was before the interception by Xposed. + * Basically the same as {@link Constructor#newInstance(Object...)}, but skips all Xposed hooks. * * @param constructor The constructor to create and initialize a new instance * @param thisObject The instance to be constructed @@ -431,8 +441,7 @@ interface MethodUnhooker { void invokeSpecial(@NonNull Constructor constructor, @NonNull T thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException; /** - * Basically the same as {@link Constructor#newInstance(Object...)}, but calls the original constructor - * as it was before the interception by Xposed. + * Basically the same as {@link Constructor#newInstance(Object...)}, but skips all Xposed hooks. * * @param The type of the constructor * @param constructor The constructor to create and initialize a new instance diff --git a/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java b/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java index 425596f..630024a 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java +++ b/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java @@ -51,37 +51,37 @@ public final int getFrameworkPrivilege() { @NonNull @Override - public final MethodUnhooker hook(@NonNull Method origin, @NonNull Class hooker) { + public final HookHandle hook(@NonNull Method origin, @NonNull Class hooker) { return mBase.hook(origin, hooker); } @NonNull @Override - public MethodUnhooker> hookClassInitializer(@NonNull Class origin, @NonNull Class hooker) { + public HookHandle> hookClassInitializer(@NonNull Class origin, @NonNull Class hooker) { return mBase.hookClassInitializer(origin, hooker); } @NonNull @Override - public MethodUnhooker> hookClassInitializer(@NonNull Class origin, int priority, @NonNull Class hooker) { + public HookHandle> hookClassInitializer(@NonNull Class origin, int priority, @NonNull Class hooker) { return mBase.hookClassInitializer(origin, priority, hooker); } @NonNull @Override - public final MethodUnhooker hook(@NonNull Method origin, int priority, @NonNull Class hooker) { + public final HookHandle hook(@NonNull Method origin, int priority, @NonNull Class hooker) { return mBase.hook(origin, priority, hooker); } @NonNull @Override - public final MethodUnhooker> hook(@NonNull Constructor origin, @NonNull Class hooker) { + public final HookHandle> hook(@NonNull Constructor origin, @NonNull Class hooker) { return mBase.hook(origin, hooker); } @NonNull @Override - public final MethodUnhooker> hook(@NonNull Constructor origin, int priority, @NonNull Class hooker) { + public final HookHandle> hook(@NonNull Constructor origin, int priority, @NonNull Class hooker) { return mBase.hook(origin, priority, hooker); } From 854af941469a69067929920311f1c9049af5a408 Mon Sep 17 00:00:00 2001 From: Nullptr Date: Mon, 28 Oct 2024 16:07:55 +0100 Subject: [PATCH 3/8] Reorder methods --- .../github/libxposed/api/XposedInterface.java | 86 +++++++++---------- .../libxposed/api/XposedInterfaceWrapper.java | 30 +++---- 2 files changed, 58 insertions(+), 58 deletions(-) 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 062a935..a846f7b 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedInterface.java +++ b/api/src/main/java/io/github/libxposed/api/XposedInterface.java @@ -283,37 +283,6 @@ interface HookHandle { @NonNull HookHandle hook(@NonNull Method origin, @NonNull Class hooker); - /** - * Hook the static initializer of a class with default priority. - *

- * Note: If the class is initialized, the hook will never be called. - *

- * - * @param origin The class to be hooked - * @param hooker The hooker class - * @return Handle for the hook - * @throws IllegalArgumentException if class has no static initializer or hooker is invalid - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - HookHandle> hookClassInitializer(@NonNull Class origin, @NonNull Class hooker); - - /** - * Hook the static initializer of a class with specified priority. - *

- * Note: If the class is initialized, the hook will never be called. - *

- * - * @param origin The class to be hooked - * @param priority The hook priority - * @param hooker The hooker class - * @return Handle for the hook - * @throws IllegalArgumentException if class has no static initializer or hooker is invalid - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - HookHandle> hookClassInitializer(@NonNull Class origin, int priority, @NonNull Class hooker); - /** * Hook a method with specified priority. * @@ -357,6 +326,37 @@ interface HookHandle { @NonNull HookHandle> hook(@NonNull Constructor origin, int priority, @NonNull Class hooker); + /** + * Hook the static initializer of a class with default priority. + *

+ * Note: If the class is initialized, the hook will never be called. + *

+ * + * @param origin The class to be hooked + * @param hooker The hooker class + * @return Handle for the hook + * @throws IllegalArgumentException if class has no static initializer or hooker is invalid + * @throws HookFailedError if hook fails due to framework internal error + */ + @NonNull + HookHandle> hookClassInitializer(@NonNull Class origin, @NonNull Class hooker); + + /** + * Hook the static initializer of a class with specified priority. + *

+ * Note: If the class is initialized, the hook will never be called. + *

+ * + * @param origin The class to be hooked + * @param priority The hook priority + * @param hooker The hooker class + * @return Handle for the hook + * @throws IllegalArgumentException if class has no static initializer or hooker is invalid + * @throws HookFailedError if hook fails due to framework internal error + */ + @NonNull + HookHandle> hookClassInitializer(@NonNull Class origin, int priority, @NonNull Class hooker); + /** * Deoptimizes a method in case hooked callee is not called because of inline. * @@ -408,6 +408,18 @@ interface HookHandle { */ void invokeOrigin(@NonNull Constructor constructor, @NonNull T thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException; + /** + * Basically the same as {@link Constructor#newInstance(Object...)}, but skips all Xposed hooks. + * + * @param The type of the constructor + * @param constructor The constructor to create and initialize a new instance + * @param args The arguments used for the construction + * @return The instance created and initialized by the constructor + * @see Constructor#newInstance(Object...) + */ + @NonNull + T newInstanceOrigin(@NonNull Constructor constructor, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException; + /** * Invokes a special (non-virtual) method on a given object instance, similar to the functionality of * {@code CallNonVirtualMethod} in JNI, which invokes an instance (nonstatic) method on a Java @@ -440,18 +452,6 @@ interface HookHandle { */ void invokeSpecial(@NonNull Constructor constructor, @NonNull T thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException; - /** - * Basically the same as {@link Constructor#newInstance(Object...)}, but skips all Xposed hooks. - * - * @param The type of the constructor - * @param constructor The constructor to create and initialize a new instance - * @param args The arguments used for the construction - * @return The instance created and initialized by the constructor - * @see Constructor#newInstance(Object...) - */ - @NonNull - T newInstanceOrigin(@NonNull Constructor constructor, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException; - /** * Creates a new instance of the given subclass, but initialize it with a parent constructor. This could * leave the object in an invalid state, where the subclass constructor are not called and the fields diff --git a/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java b/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java index 630024a..8a19c1a 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java +++ b/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java @@ -57,32 +57,32 @@ public final HookHandle hook(@NonNull Method origin, @NonNull Class HookHandle> hookClassInitializer(@NonNull Class origin, @NonNull Class hooker) { - return mBase.hookClassInitializer(origin, hooker); + public final HookHandle hook(@NonNull Method origin, int priority, @NonNull Class hooker) { + return mBase.hook(origin, priority, hooker); } @NonNull @Override - public HookHandle> hookClassInitializer(@NonNull Class origin, int priority, @NonNull Class hooker) { - return mBase.hookClassInitializer(origin, priority, hooker); + public final HookHandle> hook(@NonNull Constructor origin, @NonNull Class hooker) { + return mBase.hook(origin, hooker); } @NonNull @Override - public final HookHandle hook(@NonNull Method origin, int priority, @NonNull Class hooker) { + public final HookHandle> hook(@NonNull Constructor origin, int priority, @NonNull Class hooker) { return mBase.hook(origin, priority, hooker); } @NonNull @Override - public final HookHandle> hook(@NonNull Constructor origin, @NonNull Class hooker) { - return mBase.hook(origin, hooker); + public HookHandle> hookClassInitializer(@NonNull Class origin, @NonNull Class hooker) { + return mBase.hookClassInitializer(origin, hooker); } @NonNull @Override - public final HookHandle> hook(@NonNull Constructor origin, int priority, @NonNull Class hooker) { - return mBase.hook(origin, priority, hooker); + public HookHandle> hookClassInitializer(@NonNull Class origin, int priority, @NonNull Class hooker) { + return mBase.hookClassInitializer(origin, priority, hooker); } @Override @@ -106,6 +106,12 @@ public void invokeOrigin(@NonNull Constructor constructor, @NonNull T thi mBase.invokeOrigin(constructor, thisObject, args); } + @NonNull + @Override + public final T newInstanceOrigin(@NonNull Constructor constructor, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException { + return mBase.newInstanceOrigin(constructor, args); + } + @Nullable @Override public final Object invokeSpecial(@NonNull Method method, @NonNull Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException { @@ -117,12 +123,6 @@ public void invokeSpecial(@NonNull Constructor constructor, @NonNull T th mBase.invokeSpecial(constructor, thisObject, args); } - @NonNull - @Override - public final T newInstanceOrigin(@NonNull Constructor constructor, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException { - return mBase.newInstanceOrigin(constructor, args); - } - @NonNull @Override public final U newInstanceSpecial(@NonNull Constructor constructor, @NonNull Class subClass, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException { From a69f70789b56c782d488a0328729016d734c1945 Mon Sep 17 00:00:00 2001 From: Nullptr Date: Mon, 28 Oct 2024 16:50:36 +0100 Subject: [PATCH 4/8] Rename `getOrigin` to `getMember` --- .../io/github/libxposed/api/XposedInterface.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 a846f7b..d8cb8dd 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedInterface.java +++ b/api/src/main/java/io/github/libxposed/api/XposedInterface.java @@ -64,7 +64,7 @@ public interface XposedInterface { */ interface BeforeHookCallback { /** - * Gets the method / constructor to be hooked. + * Gets the method / constructor being hooked. */ @NonNull Member getMember(); @@ -104,7 +104,7 @@ interface BeforeHookCallback { */ interface AfterHookCallback { /** - * Gets the method / constructor to be hooked. + * Gets the method / constructor being hooked. */ @NonNull Member getMember(); @@ -217,22 +217,22 @@ interface Hooker { */ interface HookHandle { /** - * Gets the method or constructor being hooked. + * Gets the method / constructor being hooked. */ @NonNull - T getOrigin(); + T getMember(); /** * Similar to {@link Method#invoke(Object, Object...)}, but skips Xposed hooks with lower priority. * - * @param method The method or constructor to be called + * @param member The method / constructor to be called * @param thisObject For non-static calls, the {@code this} pointer, otherwise {@code null} * @param args The arguments used for the method call * @return The result returned from the invoked method * @see Method#invoke(Object, Object...) */ @Nullable - Object invoke(@NonNull T method, @Nullable Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException; + Object invoke(@NonNull T member, @Nullable Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException; /** * Cancels the hook. The behavior of calling this method multiple times is undefined. From 6767f01b2412a81d47fbc07e1d026ff0602ee4ac Mon Sep 17 00:00:00 2001 From: Nullptr Date: Tue, 29 Oct 2024 10:16:53 +0100 Subject: [PATCH 5/8] Set minSdk = 26 and refine interface --- api/build.gradle.kts | 2 +- .../github/libxposed/api/XposedInterface.java | 85 ++++--------------- .../libxposed/api/XposedInterfaceWrapper.java | 26 ++---- 3 files changed, 23 insertions(+), 90 deletions(-) diff --git a/api/build.gradle.kts b/api/build.gradle.kts index fc05e88..8896e9f 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -10,7 +10,7 @@ android { buildToolsVersion = "35.0.0" defaultConfig { - minSdk = 24 + minSdk = 26 consumerProguardFiles("proguard-rules.pro") } 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 d8cb8dd..ef6713b 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedInterface.java +++ b/api/src/main/java/io/github/libxposed/api/XposedInterface.java @@ -10,8 +10,8 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Member; import java.lang.reflect.Method; import java.nio.ByteBuffer; @@ -62,12 +62,12 @@ public interface XposedInterface { /** * Contextual interface for before invocation callbacks. */ - interface BeforeHookCallback { + interface BeforeHookCallback { /** * Gets the method / constructor being hooked. */ @NonNull - Member getMember(); + T getExecutable(); /** * Gets the {@code this} object, or {@code null} if the method is static. @@ -102,12 +102,12 @@ interface BeforeHookCallback { /** * Contextual interface for after invocation callbacks. */ - interface AfterHookCallback { + interface AfterHookCallback { /** * Gets the method / constructor being hooked. */ @NonNull - Member getMember(); + T getExecutable(); /** * Gets the {@code this} object, or {@code null} if the method is static. @@ -215,24 +215,12 @@ interface Hooker { * * @param {@link Method} or {@link Constructor} */ - interface HookHandle { + interface HookHandle { /** * Gets the method / constructor being hooked. */ @NonNull - T getMember(); - - /** - * Similar to {@link Method#invoke(Object, Object...)}, but skips Xposed hooks with lower priority. - * - * @param member The method / constructor to be called - * @param thisObject For non-static calls, the {@code this} pointer, otherwise {@code null} - * @param args The arguments used for the method call - * @return The result returned from the invoked method - * @see Method#invoke(Object, Object...) - */ - @Nullable - Object invoke(@NonNull T member, @Nullable Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException; + T getExecutable(); /** * Cancels the hook. The behavior of calling this method multiple times is undefined. @@ -271,9 +259,9 @@ interface HookHandle { int getFrameworkPrivilege(); /** - * Hook a method with default priority. + * Hook a method / constructor with default priority. * - * @param origin The method to be hooked + * @param origin The method / constructor to be hooked * @param hooker The hooker class * @return Handle for the hook * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke}, @@ -281,12 +269,12 @@ interface HookHandle { * @throws HookFailedError if hook fails due to framework internal error */ @NonNull - HookHandle hook(@NonNull Method origin, @NonNull Class hooker); + HookHandle hook(@NonNull T origin, @NonNull Class hooker); /** - * Hook a method with specified priority. + * Hook a method / constructor with specified priority. * - * @param origin The method to be hooked + * @param origin The method / constructor to be hooked * @param priority The hook priority * @param hooker The hooker class * @return Handle for the hook @@ -295,36 +283,7 @@ interface HookHandle { * @throws HookFailedError if hook fails due to framework internal error */ @NonNull - HookHandle hook(@NonNull Method origin, int priority, @NonNull Class hooker); - - /** - * Hook a constructor with default priority. - * - * @param The type of the constructor - * @param origin The constructor to be hooked - * @param hooker The hooker class - * @return Handle for the hook - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke}, - * or hooker is invalid - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - HookHandle> hook(@NonNull Constructor origin, @NonNull Class hooker); - - /** - * Hook a constructor with specified priority. - * - * @param The type of the constructor - * @param origin The constructor to be hooked - * @param priority The hook priority - * @param hooker The hooker class - * @return Handle for the hook - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke}, - * or hooker is invalid - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - HookHandle> hook(@NonNull Constructor origin, int priority, @NonNull Class hooker); + HookHandle hook(@NonNull T origin, int priority, @NonNull Class hooker); /** * Hook the static initializer of a class with default priority. @@ -358,7 +317,7 @@ interface HookHandle { HookHandle> hookClassInitializer(@NonNull Class origin, int priority, @NonNull Class hooker); /** - * Deoptimizes a method in case hooked callee is not called because of inline. + * Deoptimizes a method / constructor in case hooked callee is not called because of inline. * *

By deoptimizing the method, the method will back all callee without inlining. * For example, when a short hooked method B is invoked by method A, the callback to B is not invoked @@ -370,20 +329,10 @@ interface HookHandle { * the deoptimized callers are all you need. Otherwise, it would be better to change the hook point or * to deoptimize the whole app manually (by simply reinstalling the app without uninstall).

* - * @param method The method to deoptimize - * @return Indicate whether the deoptimizing succeed or not - */ - boolean deoptimize(@NonNull Method method); - - /** - * Deoptimizes a constructor in case hooked callee is not called because of inline. - * - * @param The type of the constructor - * @param constructor The constructor to deoptimize + * @param executable The method to deoptimize * @return Indicate whether the deoptimizing succeed or not - * @see #deoptimize(Method) */ - boolean deoptimize(@NonNull Constructor constructor); + boolean deoptimize(@NonNull Executable executable); /** * Basically the same as {@link Method#invoke(Object, Object...)}, but skips all Xposed hooks. @@ -398,7 +347,7 @@ interface HookHandle { Object invokeOrigin(@NonNull Method method, @Nullable Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException; /** - * Basically the same as {@link Constructor#newInstance(Object...)}, but skips all Xposed hooks. + * Invoke the constructor as a method, but skips all Xposed hooks. * * @param constructor The constructor to create and initialize a new instance * @param thisObject The instance to be constructed diff --git a/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java b/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java index 8a19c1a..e3099a2 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java +++ b/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java @@ -10,6 +10,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.ByteBuffer; @@ -51,25 +52,13 @@ public final int getFrameworkPrivilege() { @NonNull @Override - public final HookHandle hook(@NonNull Method origin, @NonNull Class hooker) { + public final HookHandle hook(@NonNull T origin, @NonNull Class hooker) { return mBase.hook(origin, hooker); } @NonNull @Override - public final HookHandle hook(@NonNull Method origin, int priority, @NonNull Class hooker) { - return mBase.hook(origin, priority, hooker); - } - - @NonNull - @Override - public final HookHandle> hook(@NonNull Constructor origin, @NonNull Class hooker) { - return mBase.hook(origin, hooker); - } - - @NonNull - @Override - public final HookHandle> hook(@NonNull Constructor origin, int priority, @NonNull Class hooker) { + public final HookHandle hook(@NonNull T origin, int priority, @NonNull Class hooker) { return mBase.hook(origin, priority, hooker); } @@ -86,13 +75,8 @@ public HookHandle> hookClassInitializer(@NonNull Class ori } @Override - public final boolean deoptimize(@NonNull Method method) { - return mBase.deoptimize(method); - } - - @Override - public final boolean deoptimize(@NonNull Constructor constructor) { - return mBase.deoptimize(constructor); + public final boolean deoptimize(@NonNull Executable executable) { + return mBase.deoptimize(executable); } @Nullable From bea4b68d5f7c1396561c9d011edca647ddd5859e Mon Sep 17 00:00:00 2001 From: Nullptr Date: Tue, 29 Oct 2024 10:27:48 +0100 Subject: [PATCH 6/8] Remove default priority hook --- .../github/libxposed/api/XposedInterface.java | 28 ------------------- .../libxposed/api/XposedInterfaceWrapper.java | 12 -------- 2 files changed, 40 deletions(-) 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 ef6713b..12bdb69 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedInterface.java +++ b/api/src/main/java/io/github/libxposed/api/XposedInterface.java @@ -258,19 +258,6 @@ interface HookHandle { */ int getFrameworkPrivilege(); - /** - * Hook a method / constructor with default priority. - * - * @param origin The method / constructor to be hooked - * @param hooker The hooker class - * @return Handle for the hook - * @throws IllegalArgumentException if origin is abstract, framework internal or {@link Method#invoke}, - * or hooker is invalid - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - HookHandle hook(@NonNull T origin, @NonNull Class hooker); - /** * Hook a method / constructor with specified priority. * @@ -285,21 +272,6 @@ interface HookHandle { @NonNull HookHandle hook(@NonNull T origin, int priority, @NonNull Class hooker); - /** - * Hook the static initializer of a class with default priority. - *

- * Note: If the class is initialized, the hook will never be called. - *

- * - * @param origin The class to be hooked - * @param hooker The hooker class - * @return Handle for the hook - * @throws IllegalArgumentException if class has no static initializer or hooker is invalid - * @throws HookFailedError if hook fails due to framework internal error - */ - @NonNull - HookHandle> hookClassInitializer(@NonNull Class origin, @NonNull Class hooker); - /** * Hook the static initializer of a class with specified priority. *

diff --git a/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java b/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java index e3099a2..169a8d8 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java +++ b/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java @@ -50,24 +50,12 @@ public final int getFrameworkPrivilege() { return mBase.getFrameworkPrivilege(); } - @NonNull - @Override - public final HookHandle hook(@NonNull T origin, @NonNull Class hooker) { - return mBase.hook(origin, hooker); - } - @NonNull @Override public final HookHandle hook(@NonNull T origin, int priority, @NonNull Class hooker) { return mBase.hook(origin, priority, hooker); } - @NonNull - @Override - public HookHandle> hookClassInitializer(@NonNull Class origin, @NonNull Class hooker) { - return mBase.hookClassInitializer(origin, hooker); - } - @NonNull @Override public HookHandle> hookClassInitializer(@NonNull Class origin, int priority, @NonNull Class hooker) { From 83cdd40c8bc4daf10e666d8340420d558192a864 Mon Sep 17 00:00:00 2001 From: Nullptr Date: Tue, 29 Oct 2024 10:33:46 +0100 Subject: [PATCH 7/8] Add type in example --- .../java/io/github/libxposed/api/XposedInterface.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 12bdb69..a2bc870 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedInterface.java +++ b/api/src/main/java/io/github/libxposed/api/XposedInterface.java @@ -185,23 +185,23 @@ interface AfterHookCallback { *

{@code
      *   public class ExampleHooker implements Hooker {
      *
-     *       public static void before(@NonNull BeforeHookCallback callback) {
+     *       public static void before(@NonNull BeforeHookCallback callback) {
      *           // Pre-hooking logic goes here
      *       }
      *
-     *       public static void after(@NonNull AfterHookCallback callback) {
+     *       public static void after(@NonNull AfterHookCallback callback) {
      *           // Post-hooking logic goes here
      *       }
      *   }
      *
      *   public class ExampleHookerWithContext implements Hooker {
      *
-     *       public static MyContext before(@NonNull BeforeHookCallback callback) {
+     *       public static MyContext before(@NonNull BeforeHookCallback callback) {
      *           // Pre-hooking logic goes here
      *           return new MyContext();
      *       }
      *
-     *       public static void after(@NonNull AfterHookCallback callback, MyContext context) {
+     *       public static void after(@NonNull AfterHookCallback callback, MyContext context) {
      *           // Post-hooking logic goes here
      *       }
      *   }

From 00865a09218d075f5a78dc94707f8983ebfddd07 Mon Sep 17 00:00:00 2001
From: Nullptr 
Date: Fri, 1 Nov 2024 15:50:50 +0100
Subject: [PATCH 8/8] Move onModuleLoaded out of constructor

---
 .../libxposed/api/XposedInterfaceWrapper.java     | 12 +++++++++---
 .../io/github/libxposed/api/XposedModule.java     | 15 ++-------------
 .../libxposed/api/XposedModuleInterface.java      | 11 +++++++++++
 3 files changed, 22 insertions(+), 16 deletions(-)

diff --git a/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java b/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java
index 169a8d8..2441b75 100644
--- a/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java
+++ b/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java
@@ -22,9 +22,15 @@
  */
 public class XposedInterfaceWrapper implements XposedInterface {
 
-    private final XposedInterface mBase;
-
-    XposedInterfaceWrapper(@NonNull XposedInterface base) {
+    private XposedInterface mBase;
+
+    /**
+     * Attaches the framework interface to the module. Modules should never call this method.
+     *
+     * @param base The framework interface
+     */
+    @SuppressWarnings("unused")
+    public final void attachFramework(@NonNull XposedInterface base) {
         mBase = base;
     }
 
diff --git a/api/src/main/java/io/github/libxposed/api/XposedModule.java b/api/src/main/java/io/github/libxposed/api/XposedModule.java
index b2e1a03..475a49c 100644
--- a/api/src/main/java/io/github/libxposed/api/XposedModule.java
+++ b/api/src/main/java/io/github/libxposed/api/XposedModule.java
@@ -1,21 +1,10 @@
 package io.github.libxposed.api;
 
-import androidx.annotation.NonNull;
-
 /**
  * Super class which all Xposed module entry classes should extend.
- * Entry classes will be instantiated exactly once for each process. + * Entry classes will be instantiated exactly once for each process. Modules should not do initialization + * work before {@link #onModuleLoaded(ModuleLoadedParam)} is called. */ @SuppressWarnings("unused") public abstract class XposedModule extends XposedInterfaceWrapper implements XposedModuleInterface { - /** - * Instantiates a new Xposed module.
- * When the module is loaded into the target process, the constructor will be called. - * - * @param base The implementation interface provided by the framework, should not be used by the module - * @param param Information about the process in which the module is loaded - */ - public XposedModule(@NonNull XposedInterface base, @NonNull ModuleLoadedParam param) { - super(base); - } } diff --git a/api/src/main/java/io/github/libxposed/api/XposedModuleInterface.java b/api/src/main/java/io/github/libxposed/api/XposedModuleInterface.java index 1cb548c..ef51b45 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedModuleInterface.java +++ b/api/src/main/java/io/github/libxposed/api/XposedModuleInterface.java @@ -1,5 +1,6 @@ package io.github.libxposed.api; +import android.app.AppComponentFactory; import android.content.pm.ApplicationInfo; import android.os.Build; @@ -89,6 +90,16 @@ interface PackageLoadedParam { boolean isFirstPackage(); } + /** + * Gets notified when the module is loaded into the target process.
+ * This callback is guaranteed to be called exactly once for a process before + * {@link AppComponentFactory} is created. + * + * @param param Information about the process in which the module is loaded + */ + default void onModuleLoaded(@NonNull ModuleLoadedParam param) { + } + /** * Gets notified when a package is loaded into the app process.
* This callback could be invoked multiple times for the same process on each package.