New hook API

This commit is contained in:
Nullptr 2023-07-22 12:37:27 +08:00
parent 5b4bcfe951
commit 4be04fc3ce
No known key found for this signature in database
5 changed files with 101 additions and 410 deletions

View File

@ -87,25 +87,7 @@ public class XposedContextWrapper extends ContextWrapper implements XposedInterf
*/ */
@NonNull @NonNull
@Override @Override
public final MethodUnhooker<BeforeHooker<Method>, Method> hookBefore(@NonNull Method origin, @NonNull BeforeHooker<Method> hooker) { public final MethodUnhooker<Method> hook(@NonNull Method origin, @NonNull Class<? extends Hooker> hooker) {
return getBaseContext().hookBefore(origin, hooker);
}
/**
* {@inheritDoc}
*/
@NonNull
@Override
public final MethodUnhooker<AfterHooker<Method>, Method> hookAfter(@NonNull Method origin, @NonNull AfterHooker<Method> hooker) {
return getBaseContext().hookAfter(origin, hooker);
}
/**
* {@inheritDoc}
*/
@NonNull
@Override
public final MethodUnhooker<Hooker<Method>, Method> hook(@NonNull Method origin, @NonNull Hooker<Method> hooker) {
return getBaseContext().hook(origin, hooker); return getBaseContext().hook(origin, hooker);
} }
@ -114,25 +96,7 @@ public class XposedContextWrapper extends ContextWrapper implements XposedInterf
*/ */
@NonNull @NonNull
@Override @Override
public final MethodUnhooker<BeforeHooker<Method>, Method> hookBefore(@NonNull Method origin, int priority, @NonNull BeforeHooker<Method> hooker) { public final MethodUnhooker<Method> hook(@NonNull Method origin, int priority, @NonNull Class<? extends Hooker> hooker) {
return getBaseContext().hookBefore(origin, priority, hooker);
}
/**
* {@inheritDoc}
*/
@NonNull
@Override
public final MethodUnhooker<AfterHooker<Method>, Method> hookAfter(@NonNull Method origin, int priority, @NonNull AfterHooker<Method> hooker) {
return getBaseContext().hookAfter(origin, priority, hooker);
}
/**
* {@inheritDoc}
*/
@NonNull
@Override
public final MethodUnhooker<Hooker<Method>, Method> hook(@NonNull Method origin, int priority, @NonNull Hooker<Method> hooker) {
return getBaseContext().hook(origin, priority, hooker); return getBaseContext().hook(origin, priority, hooker);
} }
@ -141,25 +105,7 @@ public class XposedContextWrapper extends ContextWrapper implements XposedInterf
*/ */
@NonNull @NonNull
@Override @Override
public final <T> MethodUnhooker<BeforeHooker<Constructor<T>>, Constructor<T>> hookBefore(@NonNull Constructor<T> origin, @NonNull BeforeHooker<Constructor<T>> hooker) { public final <T> MethodUnhooker<Constructor<T>> hook(@NonNull Constructor<T> origin, @NonNull Class<? extends Hooker> hooker) {
return getBaseContext().hookBefore(origin, hooker);
}
/**
* {@inheritDoc}
*/
@NonNull
@Override
public final <T> MethodUnhooker<AfterHooker<Constructor<T>>, Constructor<T>> hookAfter(@NonNull Constructor<T> origin, @NonNull AfterHooker<Constructor<T>> hooker) {
return getBaseContext().hookAfter(origin, hooker);
}
/**
* {@inheritDoc}
*/
@NonNull
@Override
public final <T> MethodUnhooker<Hooker<Constructor<T>>, Constructor<T>> hook(@NonNull Constructor<T> origin, @NonNull Hooker<Constructor<T>> hooker) {
return getBaseContext().hook(origin, hooker); return getBaseContext().hook(origin, hooker);
} }
@ -168,25 +114,7 @@ public class XposedContextWrapper extends ContextWrapper implements XposedInterf
*/ */
@NonNull @NonNull
@Override @Override
public final <T> MethodUnhooker<BeforeHooker<Constructor<T>>, Constructor<T>> hookBefore(@NonNull Constructor<T> origin, int priority, @NonNull BeforeHooker<Constructor<T>> hooker) { public final <T> MethodUnhooker<Constructor<T>> hook(@NonNull Constructor<T> origin, int priority, @NonNull Class<? extends Hooker> hooker) {
return getBaseContext().hookBefore(origin, priority, hooker);
}
/**
* {@inheritDoc}
*/
@NonNull
@Override
public final <T> MethodUnhooker<AfterHooker<Constructor<T>>, Constructor<T>> hookAfter(@NonNull Constructor<T> origin, int priority, @NonNull AfterHooker<Constructor<T>> hooker) {
return getBaseContext().hookAfter(origin, priority, hooker);
}
/**
* {@inheritDoc}
*/
@NonNull
@Override
public final <T> MethodUnhooker<Hooker<Constructor<T>>, Constructor<T>> hook(@NonNull Constructor<T> origin, int priority, @NonNull Hooker<Constructor<T>> hooker) {
return getBaseContext().hook(origin, priority, hooker); return getBaseContext().hook(origin, priority, hooker);
} }

View File

@ -13,10 +13,13 @@ import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.nio.ByteBuffer; 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.errors.HookFailedError;
import io.github.libxposed.api.utils.DexParser; import io.github.libxposed.api.utils.DexParser;
@ -62,239 +65,70 @@ public interface XposedInterface {
int PRIORITY_HIGHEST = 10000; 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 <T> the type parameter * <p>
* 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.
* </p>
*
* <p>
* The before invocation method should have the following signature:<br/>
* params: {@code member} - The {@link Member} object representing the method or constructor being hooked<br/>
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
* {@code thisObject} - The {@code this} pointer, or null if the method is static<br/>
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
* {@code args} - The arguments used for the method call<br/>
* returns: An {@link Hooker} object, used to save contextual information for current invocation routine
* </p>
*
* <p>
* The after invocation method should have the following signature:<br/>
* params: {@code extras} - The {@link Hooker} object returned by the before invocation method<br/>
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
* {@code result} - The result of the invocation
* </p>
*
* <p>Example usage:</p>
*
* <pre>{@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
* }
* }
* }</pre>
*/ */
interface BeforeHookCallback<T> { interface Hooker {
}
/** /**
* Gets origin. * Interface for canceling a hook.
* *
* @return the origin * @param <T> {@link Method} or {@link Constructor}
*/
interface MethodUnhooker<T> {
/**
* Gets the method or constructor being hooked.
*/ */
@NonNull @NonNull
T getOrigin(); T getOrigin();
/** /**
* Gets this. * Cancels the hook. The behavior of calling this method multiple times is undefined.
*
* @return the this
*/
@Nullable
Object getThis();
/**
* Get args object [ ].
*
* @return the object [ ]
*/
@NonNull
Object[] getArgs();
/**
* Gets arg.
*
* @param <U> the type parameter
* @param index the index
* @return the arg
*/
@Nullable
<U> U getArg(int index);
/**
* Sets arg.
*
* @param <U> the type parameter
* @param index the index
* @param value the value
*/
<U> 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 <U> the type parameter
* @param key the key
* @param value the value
* @throws ConcurrentModificationException the concurrent modification exception
*/
<U> void setExtra(@NonNull String key, @Nullable U value) throws ConcurrentModificationException;
}
/**
* The interface After hook callback.
*
* @param <T> the type parameter
*/
interface AfterHookCallback<T> {
/**
* 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 <U> the type parameter
* @param key the key
* @return the extra
*/
@Nullable
<U> U getExtra(@NonNull String key);
}
/**
* The interface Before hooker.
*
* @param <T> the type parameter
*/
interface BeforeHooker<T> {
/**
* Before.
*
* @param callback the callback
*/
void before(@NonNull BeforeHookCallback<T> callback);
}
/**
* The interface After hooker.
*
* @param <T> the type parameter
*/
interface AfterHooker<T> {
/**
* After.
*
* @param callback the callback
*/
void after(@NonNull AfterHookCallback<T> callback);
}
/**
* The interface Hooker.
*
* @param <T> the type parameter
*/
interface Hooker<T> extends BeforeHooker<T>, AfterHooker<T> {
}
/**
* The interface Method unhooker.
*
* @param <T> the type parameter
* @param <U> the type parameter
*/
interface MethodUnhooker<T, U> {
/**
* Gets origin.
*
* @return the origin
*/
@NonNull
U getOrigin();
/**
* Gets hooker.
*
* @return the hooker
*/
@NonNull
T getHooker();
/**
* Unhook.
*/ */
void unhook(); void unhook();
} }
@ -329,30 +163,6 @@ public interface XposedInterface {
*/ */
int getFrameworkPrivilege(); 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<BeforeHooker<Method>, Method> hookBefore(@NonNull Method origin, @NonNull BeforeHooker<Method> 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<AfterHooker<Method>, Method> hookAfter(@NonNull Method origin, @NonNull AfterHooker<Method> hooker);
/** /**
* Hook method unhooker. * Hook method unhooker.
* *
@ -363,33 +173,7 @@ public interface XposedInterface {
* @throws HookFailedError if hook fails due to framework internal error * @throws HookFailedError if hook fails due to framework internal error
*/ */
@NonNull @NonNull
MethodUnhooker<Hooker<Method>, Method> hook(@NonNull Method origin, @NonNull Hooker<Method> hooker); MethodUnhooker<Method> hook(@NonNull Method origin, @NonNull Class<? extends 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<BeforeHooker<Method>, Method> hookBefore(@NonNull Method origin, int priority, @NonNull BeforeHooker<Method> 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<AfterHooker<Method>, Method> hookAfter(@NonNull Method origin, int priority, @NonNull AfterHooker<Method> hooker);
/** /**
* Hook method unhooker. * Hook method unhooker.
@ -402,33 +186,7 @@ public interface XposedInterface {
* @throws HookFailedError if hook fails due to framework internal error * @throws HookFailedError if hook fails due to framework internal error
*/ */
@NonNull @NonNull
MethodUnhooker<Hooker<Method>, Method> hook(@NonNull Method origin, int priority, @NonNull Hooker<Method> hooker); MethodUnhooker<Method> hook(@NonNull Method origin, int priority, @NonNull Class<? extends Hooker> hooker);
/**
* Hook before method unhooker.
*
* @param <T> 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
<T> MethodUnhooker<BeforeHooker<Constructor<T>>, Constructor<T>> hookBefore(@NonNull Constructor<T> origin, @NonNull BeforeHooker<Constructor<T>> hooker);
/**
* Hook after method unhooker.
*
* @param <T> 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
<T> MethodUnhooker<AfterHooker<Constructor<T>>, Constructor<T>> hookAfter(@NonNull Constructor<T> origin, @NonNull AfterHooker<Constructor<T>> hooker);
/** /**
* Hook method unhooker. * Hook method unhooker.
@ -441,35 +199,7 @@ public interface XposedInterface {
* @throws HookFailedError if hook fails due to framework internal error * @throws HookFailedError if hook fails due to framework internal error
*/ */
@NonNull @NonNull
<T> MethodUnhooker<Hooker<Constructor<T>>, Constructor<T>> hook(@NonNull Constructor<T> origin, @NonNull Hooker<Constructor<T>> hooker); <T> MethodUnhooker<Constructor<T>> hook(@NonNull Constructor<T> origin, @NonNull Class<? extends Hooker> hooker);
/**
* Hook before method unhooker.
*
* @param <T> 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
<T> MethodUnhooker<BeforeHooker<Constructor<T>>, Constructor<T>> hookBefore(@NonNull Constructor<T> origin, int priority, @NonNull BeforeHooker<Constructor<T>> hooker);
/**
* Hook after method unhooker.
*
* @param <T> 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
<T> MethodUnhooker<AfterHooker<Constructor<T>>, Constructor<T>> hookAfter(@NonNull Constructor<T> origin, int priority, @NonNull AfterHooker<Constructor<T>> hooker);
/** /**
* Hook method unhooker. * Hook method unhooker.
@ -483,7 +213,7 @@ public interface XposedInterface {
* @throws HookFailedError if hook fails due to framework internal error * @throws HookFailedError if hook fails due to framework internal error
*/ */
@NonNull @NonNull
<T> MethodUnhooker<Hooker<Constructor<T>>, Constructor<T>> hook(@NonNull Constructor<T> origin, int priority, @NonNull Hooker<Constructor<T>> hooker); <T> MethodUnhooker<Constructor<T>> hook(@NonNull Constructor<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 in case hooked callee is not called because of inline.

View File

@ -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 {
}

View File

@ -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 {
}

View File

@ -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 {
}