Skip to content

Rename MethodUnhooker to HookHandle, set minSdk = 26, refine interface #35

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ android {
buildToolsVersion = "35.0.0"

defaultConfig {
minSdk = 24
minSdk = 26
consumerProguardFiles("proguard-rules.pro")
}

Expand Down
150 changes: 40 additions & 110 deletions api/src/main/java/io/github/libxposed/api/XposedInterface.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -62,12 +62,12 @@ public interface XposedInterface {
/**
* Contextual interface for before invocation callbacks.
*/
interface BeforeHookCallback {
interface BeforeHookCallback<T extends Executable> {
/**
* Gets the method / constructor to be hooked.
* Gets the method / constructor being hooked.
*/
@NonNull
Member getMember();
T getExecutable();

/**
* Gets the {@code this} object, or {@code null} if the method is static.
Expand Down Expand Up @@ -102,12 +102,12 @@ interface BeforeHookCallback {
/**
* Contextual interface for after invocation callbacks.
*/
interface AfterHookCallback {
interface AfterHookCallback<T extends Executable> {
/**
* Gets the method / constructor to be hooked.
* Gets the method / constructor being hooked.
*/
@NonNull
Member getMember();
T getExecutable();

/**
* Gets the {@code this} object, or {@code null} if the method is static.
Expand Down Expand Up @@ -185,23 +185,23 @@ interface AfterHookCallback {
* <pre>{@code
* public class ExampleHooker implements Hooker {
*
* public static void before(@NonNull BeforeHookCallback callback) {
* public static void before(@NonNull BeforeHookCallback<Method> callback) {
* // Pre-hooking logic goes here
* }
*
* public static void after(@NonNull AfterHookCallback callback) {
* public static void after(@NonNull AfterHookCallback<Method> callback) {
* // Post-hooking logic goes here
* }
* }
*
* public class ExampleHookerWithContext implements Hooker {
*
* public static MyContext before(@NonNull BeforeHookCallback callback) {
* public static MyContext before(@NonNull BeforeHookCallback<Method> callback) {
* // Pre-hooking logic goes here
* return new MyContext();
* }
*
* public static void after(@NonNull AfterHookCallback callback, MyContext context) {
* public static void after(@NonNull AfterHookCallback<Method> callback, MyContext context) {
* // Post-hooking logic goes here
* }
* }
Expand All @@ -211,16 +211,16 @@ interface Hooker {
}

/**
* Interface for canceling a hook.
* Handle for a hook.
*
* @param <T> {@link Method} or {@link Constructor}
*/
interface MethodUnhooker<T> {
interface HookHandle<T extends Executable> {
/**
* Gets the method or constructor being hooked.
* Gets the method / constructor being hooked.
*/
@NonNull
T getOrigin();
T getExecutable();

/**
* Cancels the hook. The behavior of calling this method multiple times is undefined.
Expand Down Expand Up @@ -259,32 +259,18 @@ interface MethodUnhooker<T> {
int getFrameworkPrivilege();

/**
* Hook a method with default priority.
* Hook a method / constructor with specified priority.
*
* @param origin The method to be hooked
* @param hooker The hooker class
* @return Unhooker for canceling the hook
* @param origin The method / 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
MethodUnhooker<Method> hook(@NonNull Method origin, @NonNull Class<? extends Hooker> hooker);

/**
* Hook the static initializer of a class with default priority.
* <p>
* Note: If the class is initialized, the hook will never be called.
* </p>
*
* @param origin The class to be hooked
* @param hooker The hooker class
* @return Unhooker for canceling 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
<T> MethodUnhooker<Constructor<T>> hookClassInitializer(@NonNull Class<T> origin, @NonNull Class<? extends Hooker> hooker);
<T extends Executable> HookHandle<T> hook(@NonNull T origin, int priority, @NonNull Class<? extends Hooker> hooker);

/**
* Hook the static initializer of a class with specified priority.
Expand All @@ -295,58 +281,15 @@ interface MethodUnhooker<T> {
* @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
<T> MethodUnhooker<Constructor<T>> hookClassInitializer(@NonNull Class<T> origin, int priority, @NonNull Class<? extends Hooker> hooker);

/**
* Hook a method with specified priority.
*
* @param origin The method to be hooked
* @param priority The hook priority
* @param hooker The hooker class
* @return Unhooker for canceling 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<Method> hook(@NonNull Method origin, int priority, @NonNull Class<? extends Hooker> hooker);

/**
* Hook a constructor with default priority.
*
* @param <T> The type of the constructor
* @param origin The constructor to be hooked
* @param hooker The hooker class
* @return Unhooker for canceling 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
<T> MethodUnhooker<Constructor<T>> hook(@NonNull Constructor<T> origin, @NonNull Class<? extends Hooker> hooker);

/**
* Hook a constructor with specified priority.
*
* @param <T> The type of the constructor
* @param origin The constructor to be hooked
* @param priority The hook priority
* @param hooker The hooker class
* @return Unhooker for canceling 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
<T> MethodUnhooker<Constructor<T>> hook(@NonNull Constructor<T> origin, int priority, @NonNull Class<? extends Hooker> hooker);
<T> HookHandle<Constructor<T>> hookClassInitializer(@NonNull Class<T> origin, int priority, @NonNull Class<? extends Hooker> 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.
*
* <p>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
Expand All @@ -358,24 +301,13 @@ interface MethodUnhooker<T> {
* 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).</p>
*
* @param method The method to deoptimize
* @param executable The method to deoptimize
* @return Indicate whether the deoptimizing succeed or not
*/
boolean deoptimize(@NonNull Method method);
boolean deoptimize(@NonNull Executable executable);

/**
* Deoptimizes a constructor in case hooked callee is not called because of inline.
*
* @param <T> The type of the constructor
* @param constructor The constructor to deoptimize
* @return Indicate whether the deoptimizing succeed or not
* @see #deoptimize(Method)
*/
<T> boolean deoptimize(@NonNull Constructor<T> 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}
Expand All @@ -387,8 +319,7 @@ interface MethodUnhooker<T> {
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.
* 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
Expand All @@ -398,6 +329,18 @@ interface MethodUnhooker<T> {
*/
<T> void invokeOrigin(@NonNull Constructor<T> constructor, @NonNull T thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException;

/**
* Basically the same as {@link Constructor#newInstance(Object...)}, but skips all Xposed hooks.
*
* @param <T> 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> T newInstanceOrigin(@NonNull Constructor<T> 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 CallNonVirtual<type>Method} in JNI, which invokes an instance (nonstatic) method on a Java
Expand Down Expand Up @@ -430,19 +373,6 @@ interface MethodUnhooker<T> {
*/
<T> void invokeSpecial(@NonNull Constructor<T> 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.
*
* @param <T> 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> T newInstanceOrigin(@NonNull Constructor<T> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -21,9 +22,15 @@
*/
public class XposedInterfaceWrapper implements XposedInterface {

private final XposedInterface mBase;
private XposedInterface mBase;

XposedInterfaceWrapper(@NonNull XposedInterface base) {
/**
* 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;
}

Expand Down Expand Up @@ -51,48 +58,19 @@ public final int getFrameworkPrivilege() {

@NonNull
@Override
public final MethodUnhooker<Method> hook(@NonNull Method origin, @NonNull Class<? extends Hooker> hooker) {
return mBase.hook(origin, hooker);
}

@NonNull
@Override
public <T> MethodUnhooker<Constructor<T>> hookClassInitializer(@NonNull Class<T> origin, @NonNull Class<? extends Hooker> hooker) {
return mBase.hookClassInitializer(origin, hooker);
}

@NonNull
@Override
public <T> MethodUnhooker<Constructor<T>> hookClassInitializer(@NonNull Class<T> origin, int priority, @NonNull Class<? extends Hooker> hooker) {
return mBase.hookClassInitializer(origin, priority, hooker);
}

@NonNull
@Override
public final MethodUnhooker<Method> hook(@NonNull Method origin, int priority, @NonNull Class<? extends Hooker> hooker) {
public final <T extends Executable> HookHandle<T> hook(@NonNull T origin, int priority, @NonNull Class<? extends Hooker> hooker) {
return mBase.hook(origin, priority, hooker);
}

@NonNull
@Override
public final <T> MethodUnhooker<Constructor<T>> hook(@NonNull Constructor<T> origin, @NonNull Class<? extends Hooker> hooker) {
return mBase.hook(origin, hooker);
}

@NonNull
@Override
public final <T> MethodUnhooker<Constructor<T>> hook(@NonNull Constructor<T> origin, int priority, @NonNull Class<? extends Hooker> hooker) {
return mBase.hook(origin, priority, hooker);
}

@Override
public final boolean deoptimize(@NonNull Method method) {
return mBase.deoptimize(method);
public <T> HookHandle<Constructor<T>> hookClassInitializer(@NonNull Class<T> origin, int priority, @NonNull Class<? extends Hooker> hooker) {
return mBase.hookClassInitializer(origin, priority, hooker);
}

@Override
public final <T> boolean deoptimize(@NonNull Constructor<T> constructor) {
return mBase.deoptimize(constructor);
public final boolean deoptimize(@NonNull Executable executable) {
return mBase.deoptimize(executable);
}

@Nullable
Expand All @@ -106,6 +84,12 @@ public <T> void invokeOrigin(@NonNull Constructor<T> constructor, @NonNull T thi
mBase.invokeOrigin(constructor, thisObject, args);
}

@NonNull
@Override
public final <T> T newInstanceOrigin(@NonNull Constructor<T> 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 {
Expand All @@ -117,12 +101,6 @@ public <T> void invokeSpecial(@NonNull Constructor<T> constructor, @NonNull T th
mBase.invokeSpecial(constructor, thisObject, args);
}

@NonNull
@Override
public final <T> T newInstanceOrigin(@NonNull Constructor<T> constructor, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException {
return mBase.newInstanceOrigin(constructor, args);
}

@NonNull
@Override
public final <T, U> U newInstanceSpecial(@NonNull Constructor<T> constructor, @NonNull Class<U> subClass, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException {
Expand Down
Loading