diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 059e414..7c8f37c 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -7,11 +7,11 @@ plugins { android { namespace = "io.github.libxposed.api" compileSdk = 36 - buildToolsVersion = "35.0.0" + buildToolsVersion = "36.1.0" androidResources.enable = false defaultConfig { - minSdk = 24 + minSdk = 26 consumerProguardFiles("proguard-rules.pro") } @@ -20,8 +20,8 @@ android { } compileOptions { - targetCompatibility = JavaVersion.VERSION_1_8 - sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_21 + sourceCompatibility = JavaVersion.VERSION_21 } publishing { @@ -32,12 +32,17 @@ android { } } +dependencies { + compileOnly(libs.annotation) + compileOnly(libs.kotlin.stdlib) +} + publishing { publications { register("api") { artifactId = "api" group = "io.github.libxposed" - version = "100" + version = "101.0.0" pom { name.set("api") description.set("Modern Xposed API") @@ -89,9 +94,3 @@ signing { sign(publishing.publications) } } - - -dependencies { - compileOnly(libs.annotation) - lintPublish(project(":checks")) -} diff --git a/api/proguard-rules.pro b/api/proguard-rules.pro index ac904d7..ae38534 100644 --- a/api/proguard-rules.pro +++ b/api/proguard-rules.pro @@ -1,8 +1,10 @@ -keep class io.github.libxposed.** { *; } --keepclassmembers,allowoptimization class ** implements io.github.libxposed.api.XposedInterface$Hooker { - public static *** before(); - 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, ***); +-keepclassmembers,allowoptimization class ** implements io.github.libxposed.api.XposedInterface$MethodHooker { + java.lang.Object intercept(io.github.libxposed.api.XposedInterface$MethodChain); +} +-keepclassmembers,allowoptimization class ** implements io.github.libxposed.api.XposedInterface$VoidMethodHooker { + void intercept(io.github.libxposed.api.XposedInterface$MethodChain); +} +-keepclassmembers,allowoptimization class ** implements io.github.libxposed.api.XposedInterface$CtorHooker { + void intercept(io.github.libxposed.api.XposedInterface$CtorChain); } 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 431eadd..74238fa 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedInterface.java +++ b/api/src/main/java/io/github/libxposed/api/XposedInterface.java @@ -8,15 +8,13 @@ import androidx.annotation.Nullable; 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; +import java.util.List; -import io.github.libxposed.api.errors.HookFailedError; -import io.github.libxposed.api.utils.DexParser; +import io.github.libxposed.api.error.HookFailedError; /** * Xposed interface for modules to operate on application processes. @@ -24,442 +22,384 @@ @SuppressWarnings("unused") public interface XposedInterface { /** - * SDK API version. + * The API version of this library. This is a static value for the framework. + * Modules should use {@link #getApiVersion()} to check the API version at runtime. */ - int API = 100; + int LIB_API = 101; /** - * Indicates that the framework is running as root. + * The framework has the capability to hook system_server and other system processes. */ - int FRAMEWORK_PRIVILEGE_ROOT = 0; + long PROP_CAP_SYSTEM = 1L; /** - * Indicates that the framework is running in a container with a fake system_server. + * The framework provides remote preferences and remote files support. */ - int FRAMEWORK_PRIVILEGE_CONTAINER = 1; + long PROP_CAP_REMOTE = 1L << 1; /** - * Indicates that the framework is running as a different app, which may have at most shell permission. + * The framework disallows accessing Xposed API via reflection or dynamically loaded code. */ - int FRAMEWORK_PRIVILEGE_APP = 2; - /** - * Indicates that the framework is embedded in the hooked app, - * which means {@link #getRemotePreferences} will be null and remote file is unsupported. - */ - int FRAMEWORK_PRIVILEGE_EMBEDDED = 3; + long PROP_RT_API_PROTECTION = 1L << 2; /** * The default hook priority. */ int PRIORITY_DEFAULT = 50; /** - * Execute the hook callback late. + * Execute at the end of the interception chain. */ - int PRIORITY_LOWEST = -10000; + int PRIORITY_LOWEST = Integer.MIN_VALUE; /** - * Execute the hook callback early. + * Execute at the beginning of the interception chain. */ - int PRIORITY_HIGHEST = 10000; + int PRIORITY_HIGHEST = Integer.MAX_VALUE; /** - * Contextual interface for before invocation callbacks. + * Invoker for a method or constructor. */ - interface BeforeHookCallback { + interface Invoker, U extends Executable> { /** - * Gets the method / constructor to be hooked. + * Type of the invoker, which determines the hook chain to be invoked */ - @NonNull - Member getMember(); + sealed interface Type permits Type.Origin, Type.Chain { + /** + * A convenience constant for {@link Origin}. + */ + Origin ORIGIN = new Origin(); + + /** + * Invokes the original executable, skipping all hooks. + */ + record Origin() implements Type { + } + + /** + * Invokes the executable starting from the middle of the hook chain, skipping all + * hooks with priority higher than the given value. + * + * @param maxPriority The maximum priority of hooks to include in the chain + */ + record Chain(int maxPriority) implements Type { + /** + * Invoking the executable with full hook chain. + */ + public static final Chain FULL = new Chain(PRIORITY_HIGHEST); + } + } /** - * Gets the {@code this} object, or {@code null} if the method is static. + * Sets the type of the invoker, which determines the hook chain to be invoked */ - @Nullable - Object getThisObject(); + T setType(@NonNull Type type); /** - * Gets the arguments passed to the method / constructor. You can modify the arguments. + * Invokes the method (or the constructor as a method) through the hook chain determined by + * the invoker's type. + * + * @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 + *

For void methods and constructors, always returns {@code null}.

+ * @see Method#invoke(Object, Object...) */ - @NonNull - Object[] getArgs(); + Object invoke(Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException; /** - * Sets the return value of the method and skip the invocation. If the procedure is a constructor, - * the {@code result} param will be ignored. - * Note that the after invocation callback will still be called. + * Invokes the special (non-virtual) method (or the constructor as a method) on a given object + * instance, similar to the functionality of {@code CallNonVirtualMethod} in JNI, which invokes + * an instance (nonstatic) method on a Java object. This method is useful when you need to call + * a specific method on an object, bypassing any overridden methods in subclasses and + * directly invoking the method defined in the specified class. * - * @param result The return value + *

This method is useful when you need to call {@code super.xxx()} in a hooked constructor.

+ * + * @param thisObject The {@code this} pointer + * @param args The arguments used for the method call + * @return The result returned from the invoked method + *

For void methods and constructors, always returns {@code null}.

+ * @see Method#invoke(Object, Object...) */ - void returnAndSkip(@Nullable Object result); + Object invokeSpecial(@NonNull Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException; + } + /** + * Invoker for a constructor. + * + * @param The type of the constructor + */ + interface CtorInvoker extends Invoker, Constructor> { /** - * Throw an exception from the method / constructor and skip the invocation. - * Note that the after invocation callback will still be called. + * Creates a new instance through the hook chain determined by the invoker's type. * - * @param throwable The exception to be thrown + * @param args The arguments used for the construction + * @return The instance created and initialized by the constructor + * @see Constructor#newInstance(Object...) */ - void throwAndSkip(@Nullable Throwable throwable); + @NonNull + T newInstance(Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException; + + /** + * Creates a new instance of the given subclass, but initializes it with a parent constructor. This could + * leave the object in an invalid state, where the subclass constructor is not called and the fields + * of the subclass are not initialized. + * + *

This method is useful when you need to initialize some fields in the subclass by yourself.

+ * + * @param The type of the subclass + * @param subClass The subclass to create a new instance + * @param args The arguments used for the construction + * @return The instance of subclass initialized by the constructor + * @see Constructor#newInstance(Object...) + */ + @NonNull + U newInstanceSpecial(@NonNull Class subClass, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException; } /** - * Contextual interface for after invocation callbacks. + * Interceptor chain for a method or constructor. */ - interface AfterHookCallback { + interface Chain { /** - * Gets the method / constructor to be hooked. + * Gets the method / constructor being hooked. */ @NonNull - Member getMember(); + Executable getExecutable(); /** - * Gets the {@code this} object, or {@code null} if the method is static. + * Gets the {@code this} pointer for the call, or {@code null} for static methods. */ - @Nullable Object getThisObject(); /** - * Gets all arguments passed to the method / constructor. + * Gets the arguments. The returned list is immutable. If you want to change the arguments, you + * should call {@code proceed(Object...)} or {@code proceedWith(Object, Object...)} with the new + * arguments. */ @NonNull - Object[] getArgs(); + List getArgs(); /** - * Gets the return value of the method or the before invocation callback. If the procedure is a - * constructor, a void method or an exception was thrown, the return value will be {@code null}. + * Gets the argument at the given index. + * + * @param index The argument index + * @return The argument at the given index + * @throws IndexOutOfBoundsException if index is out of bounds + * @throws ClassCastException if the argument cannot be cast to the expected type */ - @Nullable - Object getResult(); + Object getArg(int index) throws IndexOutOfBoundsException, ClassCastException; /** - * Gets the exception thrown by the method / constructor or the before invocation callback. If the - * procedure call was successful, the return value will be {@code null}. + * Proceeds to the next interceptor in the chain with the same arguments and {@code this} pointer. + * + * @return The result returned from next interceptor or the original executable if current + * interceptor is the last one in the chain. + *

For void methods and constructors, always returns {@code null}.

+ * @throws Throwable if any interceptor or the original executable throws an exception */ - @Nullable - Throwable getThrowable(); + Object proceed() throws Throwable; /** - * Gets whether the invocation was skipped by the before invocation callback. + * Proceeds to the next interceptor in the chain with the given arguments and the same {@code this} pointer. + * + * @param args The arguments used for the call + * @return The result returned from next interceptor or the original executable if current + * interceptor is the last one in the chain. + *

For void methods and constructors, always returns {@code null}.

+ * @throws Throwable if any interceptor or the original executable throws an exception */ - boolean isSkipped(); + Object proceed(@NonNull Object[] args) throws Throwable; /** - * Sets the return value of the method and skip the invocation. If the procedure is a constructor, - * the {@code result} param will be ignored. + * Proceeds to the next interceptor in the chain with the same arguments and given {@code this} pointer. + * Static method interceptors should not call this. * - * @param result The return value + * @param thisObject The {@code this} pointer for the call + * @return The result returned from next interceptor or the original executable if current + * interceptor is the last one in the chain. + *

For void methods and constructors, always returns {@code null}.

+ * @throws Throwable if any interceptor or the original executable throws an exception */ - void setResult(@Nullable Object result); + Object proceedWith(@NonNull Object thisObject) throws Throwable; /** - * Sets the exception thrown by the method / constructor. + * Proceeds to the next interceptor in the chain with the given arguments and {@code this} pointer. + * Static method interceptors should not call this. * - * @param throwable The exception to be thrown. + * @param thisObject The {@code this} pointer for the call + * @param args The arguments used for the call + * @return The result returned from next interceptor or the original executable if current + * interceptor is the last one in the chain. + *

For void methods and constructors, always returns {@code null}.

+ * @throws Throwable if any interceptor or the original executable throws an exception */ - void setThrowable(@Nullable Throwable throwable); + Object proceedWith(@NonNull Object thisObject, @NonNull Object[] args) throws Throwable; } /** - * Interface for method / constructor hooking. Xposed modules should define their own hooker class - * and implement this interface. Normally, a hooker class corresponds to a method / constructor, but - * there could also be a single hooker class for all of them. By this way you can implement an interface - * like the old API. - * - *

- * Classes implementing this interface should should provide two public static methods named - * before and after for before invocation and after invocation respectively. - *

- * - *

- * The before invocation method should have the following signature:
- * Param {@code callback}: The {@link BeforeHookCallback} of the procedure call.
- * Return value: If you want to save contextual information of one procedure call between the before - * and after callback, it could be a self-defined class, otherwise it should be {@code void}. - *

- * - *

- * The after invocation method should have the following signature:
- * Param {@code callback}: The {@link AfterHookCallback} of the procedure call.
- * Param {@code context} (optional): The contextual object returned by the before invocation. - *

- * - *

Example usage:

- * - *
{@code
-     *   public class ExampleHooker implements Hooker {
-     *
-     *       public static void before(@NonNull BeforeHookCallback callback) {
-     *           // Pre-hooking logic goes here
-     *       }
-     *
-     *       public static void after(@NonNull AfterHookCallback callback) {
-     *           // Post-hooking logic goes here
-     *       }
-     *   }
-     *
-     *   public class ExampleHookerWithContext implements Hooker {
-     *
-     *       public static MyContext before(@NonNull BeforeHookCallback callback) {
-     *           // Pre-hooking logic goes here
-     *           return new MyContext();
-     *       }
-     *
-     *       public static void after(@NonNull AfterHookCallback callback, MyContext context) {
-     *           // Post-hooking logic goes here
-     *       }
-     *   }
-     * }
+ * Hooker for a method or constructor. */ interface Hooker { + /** + * Intercepts a method / constructor call. + * + * @param chain The interceptor chain for the call + * @return The result to be returned from the interceptor. If the hooker does not want to + * change the result, it should call {@code chain.proceed()} and return its result. + *

For void methods and constructors, the return value is ignored by the framework.

+ * @throws Throwable Throw any exception from the interceptor. The exception will + * propagate to the caller if not caught by any interceptor. + */ + Object intercept(@NonNull Chain chain) throws Throwable; } /** - * Interface for canceling a hook. - * - * @param {@link Method} or {@link Constructor} + * Handle for a hook. */ - interface MethodUnhooker { + interface HookHandle { /** - * Gets the method or constructor being hooked. + * Gets the method / constructor being hooked. */ @NonNull - T getOrigin(); + Executable getExecutable(); /** - * Cancels the hook. The behavior of calling this method multiple times is undefined. + * Cancels the hook. This method is idempotent. It is safe to call this method multiple times. */ void unhook(); } + /** + * Builder for configuring a hook. + */ + interface HookBuilder { + /** + * Sets the priority of the hook. Hooks with higher priority will be called before hooks with lower + * priority. The default priority is {@link XposedInterface#PRIORITY_DEFAULT}. + * + * @param priority The priority of the hook + * @return The builder itself for chaining + */ + HookBuilder setPriority(int priority); + + /** + * Sets the hooker for the method / constructor and builds the hook. + * + * @param hooker The hooker object + * @return The handle for the hook + * @throws IllegalArgumentException if origin is framework internal or {@link Constructor#newInstance}, + * or hooker is invalid + * @throws HookFailedError if hook fails due to framework internal error + */ + @NonNull + HookHandle intercept(@NonNull Hooker hooker); + } + + /** + * Gets the runtime Xposed API version. Framework implementations must not override this method. + */ + default int getApiVersion() { + return LIB_API; + } + /** * Gets the Xposed framework name of current implementation. - * - * @return Framework name */ @NonNull String getFrameworkName(); /** * Gets the Xposed framework version of current implementation. - * - * @return Framework version */ @NonNull String getFrameworkVersion(); /** * Gets the Xposed framework version code of current implementation. - * - * @return Framework version code */ long getFrameworkVersionCode(); /** - * Gets the Xposed framework privilege of current implementation. - * - * @return Framework privilege + * Gets the Xposed framework properties. + * Properties with prefix {@code PROP_RT_} may change among launches. */ - int getFrameworkPrivilege(); + long getFrameworkProperties(); /** - * Hook a method with default priority. + * Hook a method / constructor. * - * @param origin The method 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 + * @param origin The executable to be hooked + * @return The builder for the hook */ @NonNull - MethodUnhooker hook(@NonNull Method origin, @NonNull Class hooker); + HookBuilder hook(@NonNull Executable origin); /** - * Hook the static initializer of a class with default priority. - *

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

+ * Hook the static initializer ({@code }) of a class. * - * @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 - MethodUnhooker> 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 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 - MethodUnhooker> hookClassInitializer(@NonNull Class origin, int priority, @NonNull Class hooker); - - /** - * Hook a method with specified priority. + *

The static initializer is treated as a regular {@code static void()} method with no parameters. + * Accordingly, in the {@link Chain} passed to the hooker:

+ *
    + *
  • {@link Chain#getExecutable()} returns a synthetic {@link Method} representing + * the static initializer.
  • + *
  • {@link Chain#getThisObject()} always returns {@code null}.
  • + *
  • {@link Chain#getArgs()} returns an empty list.
  • + *
  • {@link Chain#proceed()} returns {@code null}.
  • + *
* - * @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 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 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> hook(@NonNull Constructor origin, @NonNull Class hooker); - - /** - * Hook a constructor with specified priority. + *

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

* - * @param 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 + * @param origin The class whose static initializer is to be hooked + * @return The builder for the hook */ @NonNull - MethodUnhooker> hook(@NonNull Constructor origin, int priority, @NonNull Class hooker); + HookBuilder hookClassInitializer(@NonNull Class origin); /** - * 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. + *

By deoptimizing the method, the runtime will fall back to calling all callees without inlining. * For example, when a short hooked method B is invoked by method A, the callback to B is not invoked * after hooking, which may mean A has inlined B inside its method body. To force A to call the hooked B, * you can deoptimize A and then your hook can take effect.

* - *

Generally, you need to find all the callers of your hooked callee and that can be hardly achieve - * (but you can still search all callers by using {@link DexParser}). Use this method if you are sure - * 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. + *

Generally, you need to find all the callers of your hooked callee, and that can hardly be achieved + * (but you can still search all callers by using DexKit). + * Use this method if you are sure 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 The type of the constructor - * @param constructor The constructor to deoptimize + * @param executable The method / constructor to deoptimize * @return Indicate whether the deoptimizing succeed or not - * @see #deoptimize(Method) - */ - 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. - * - * @param method The method 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 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. - * - * @param constructor The constructor to create and initialize a new instance - * @param thisObject The instance to be constructed - * @param args The arguments used for the construction - * @param The type of the instance - * @see Constructor#newInstance(Object...) - */ - void invokeOrigin(@NonNull Constructor constructor, @NonNull T thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException; - - /** - * 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 - * object. This method is useful when you need to call a specific method on an object, bypassing any - * overridden methods in subclasses and directly invoking the method defined in the specified class. - * - *

This method is useful when you need to call {@code super.xxx()} in a hooked constructor.

- * - * @param method The method 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 invokeSpecial(@NonNull Method method, @NonNull Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException; + boolean deoptimize(@NonNull Executable executable); /** - * 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 - * object. This method is useful when you need to call a specific method on an object, bypassing any - * overridden methods in subclasses and directly invoking the method defined in the specified class. + * Get a method invoker for the given method. The default type of the invoker is + * {@link Invoker.Type.Chain#FULL}. * - *

This method is useful when you need to call {@code super.xxx()} in a hooked constructor.

- * - * @param constructor The constructor to create and initialize a new instance - * @param thisObject The instance to be constructed - * @param args The arguments used for the construction - * @see Constructor#newInstance(Object...) + * @param method The method to get the invoker for + * @return The method invoker */ - void invokeSpecial(@NonNull Constructor constructor, @NonNull T thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException; + @NonNull + Invoker getInvoker(@NonNull Method method); /** - * Basically the same as {@link Constructor#newInstance(Object...)}, but calls the original constructor - * as it was before the interception by Xposed. + * Get a constructor invoker for the given constructor. The default type of the invoker is + * {@link Invoker.Type.Chain#FULL}. * + * @param constructor The constructor to get the invoker for * @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...) + * @return The constructor invoker */ @NonNull - T newInstanceOrigin(@NonNull Constructor constructor, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException; + CtorInvoker getInvoker(@NonNull Constructor constructor); /** - * 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 - * of the subclass are not initialized. - * - *

This method is useful when you need to initialize some fields in the subclass by yourself.

+ * Writes a message to the Xposed log. * - * @param The type of the parent constructor - * @param The type of the subclass - * @param constructor The parent constructor to initialize a new instance - * @param subClass The subclass to create a new instance - * @param args The arguments used for the construction - * @return The instance of subclass initialized by the constructor - * @see Constructor#newInstance(Object...) + * @param priority The log priority, see {@link android.util.Log} + * @param tag The log tag + * @param msg The log message */ - @NonNull - U newInstanceSpecial(@NonNull Constructor constructor, @NonNull Class subClass, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException; + void log(int priority, @Nullable String tag, @NonNull String msg); /** * Writes a message to the Xposed log. @@ -471,42 +411,11 @@ interface MethodUnhooker { */ void log(int priority, @Nullable String tag, @NonNull String msg, @Nullable Throwable tr); - /** - * Writes a message to the Xposed log. - * @deprecated Use {@link #log(int, String, String, Throwable)} instead. - * This method is kept for compatibility with old hooker classes and will be removed in first release version. - * - * @param message The log message - */ - @Deprecated - void log(@NonNull String message); - - /** - * Writes a message with a stack trace to the Xposed log. - * @deprecated Use {@link #log(int, String, String, Throwable)} instead. - * - * @param message The log message - * @param throwable The Throwable object for the stack trace - */ - @Deprecated - void log(@NonNull String message, @NonNull Throwable throwable); - - /** - * Parse a dex file in memory. - * - * @param dexData The content of the dex file - * @param includeAnnotations Whether to include annotations - * @return The {@link DexParser} of the dex file - * @throws IOException if the dex file is invalid - */ - @Nullable - DexParser parseDex(@NonNull ByteBuffer dexData, boolean includeAnnotations) throws IOException; - /** * Gets the application info of the module. */ @NonNull - ApplicationInfo getApplicationInfo(); + ApplicationInfo getModuleApplicationInfo(); /** * Gets remote preferences stored in Xposed framework. Note that those are read-only in hooked apps. 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 feb8cea..20b10a8 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java +++ b/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java @@ -8,169 +8,139 @@ import androidx.annotation.Nullable; import java.io.FileNotFoundException; -import java.io.IOException; import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Executable; import java.lang.reflect.Method; -import java.nio.ByteBuffer; - -import io.github.libxposed.api.utils.DexParser; /** - * Wrap of {@link XposedInterface} used by the modules for the purpose of shielding framework implementation details. + * Wrapper of {@link XposedInterface} used by modules to shield framework implementation details. */ public class XposedInterfaceWrapper implements XposedInterface { - private final XposedInterface mBase; - - XposedInterfaceWrapper(@NonNull XposedInterface base) { + private volatile 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) { + if (mBase != null) { + throw new IllegalStateException("Framework already attached"); + } mBase = base; } + private void ensureAttached() { + if (mBase == null) { + throw new IllegalStateException("Framework not attached"); + } + } + + @Override + public final int getApiVersion() { + ensureAttached(); + return XposedInterface.super.getApiVersion(); + } + @NonNull @Override public final String getFrameworkName() { + ensureAttached(); return mBase.getFrameworkName(); } @NonNull @Override public final String getFrameworkVersion() { + ensureAttached(); return mBase.getFrameworkVersion(); } @Override public final long getFrameworkVersionCode() { + ensureAttached(); return mBase.getFrameworkVersionCode(); } @Override - public final int getFrameworkPrivilege() { - return mBase.getFrameworkPrivilege(); - } - - @NonNull - @Override - public final MethodUnhooker hook(@NonNull Method origin, @NonNull Class hooker) { - return mBase.hook(origin, hooker); - } - - @NonNull - @Override - public MethodUnhooker> hookClassInitializer(@NonNull Class origin, @NonNull Class hooker) { - return mBase.hookClassInitializer(origin, hooker); + public final long getFrameworkProperties() { + ensureAttached(); + return mBase.getFrameworkProperties(); } @NonNull @Override - public MethodUnhooker> hookClassInitializer(@NonNull Class origin, int priority, @NonNull Class hooker) { - return mBase.hookClassInitializer(origin, priority, hooker); + public final HookBuilder hook(@NonNull Executable origin) { + ensureAttached(); + return mBase.hook(origin); } @NonNull @Override - public final MethodUnhooker hook(@NonNull Method origin, int priority, @NonNull Class hooker) { - return mBase.hook(origin, priority, hooker); + public final HookBuilder hookClassInitializer(@NonNull Class origin) { + ensureAttached(); + return mBase.hookClassInitializer(origin); } - @NonNull @Override - public final MethodUnhooker> hook(@NonNull Constructor origin, @NonNull Class hooker) { - return mBase.hook(origin, hooker); + public final boolean deoptimize(@NonNull Executable executable) { + ensureAttached(); + return mBase.deoptimize(executable); } @NonNull @Override - public final MethodUnhooker> hook(@NonNull Constructor origin, int priority, @NonNull Class hooker) { - return mBase.hook(origin, priority, hooker); - } - - @Override - public final boolean deoptimize(@NonNull Method method) { - return mBase.deoptimize(method); - } - - @Override - public final boolean deoptimize(@NonNull Constructor constructor) { - return mBase.deoptimize(constructor); - } - - @Nullable - @Override - public final Object invokeOrigin(@NonNull Method method, @Nullable Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException { - return mBase.invokeOrigin(method, thisObject, args); - } - - @Override - public void invokeOrigin(@NonNull Constructor constructor, @NonNull T thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException { - mBase.invokeOrigin(constructor, thisObject, args); - } - - @Nullable - @Override - public final Object invokeSpecial(@NonNull Method method, @NonNull Object thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException { - return mBase.invokeSpecial(method, thisObject, args); - } - - @Override - public void invokeSpecial(@NonNull Constructor constructor, @NonNull T thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException { - mBase.invokeSpecial(constructor, thisObject, args); + public final Invoker getInvoker(@NonNull Method method) { + ensureAttached(); + return mBase.getInvoker(method); } @NonNull @Override - public final T newInstanceOrigin(@NonNull Constructor constructor, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException { - return mBase.newInstanceOrigin(constructor, args); + public final CtorInvoker getInvoker(@NonNull Constructor constructor) { + ensureAttached(); + return mBase.getInvoker(constructor); } - @NonNull @Override - public final U newInstanceSpecial(@NonNull Constructor constructor, @NonNull Class subClass, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException { - return mBase.newInstanceSpecial(constructor, subClass, args); + public final void log(int priority, @Nullable String tag, @NonNull String msg) { + ensureAttached(); + mBase.log(priority, tag, msg); } @Override public final void log(int priority, @Nullable String tag, @NonNull String msg, @Nullable Throwable tr) { + ensureAttached(); mBase.log(priority, tag, msg, tr); } - @Override - public final void log(@NonNull String message) { - mBase.log(message); - } - - @Override - public final void log(@NonNull String message, @NonNull Throwable throwable) { - mBase.log(message, throwable); - } - - @Nullable - @Override - public final DexParser parseDex(@NonNull ByteBuffer dexData, boolean includeAnnotations) throws IOException { - return mBase.parseDex(dexData, includeAnnotations); - } - @NonNull @Override - public SharedPreferences getRemotePreferences(@NonNull String name) { + public final SharedPreferences getRemotePreferences(@NonNull String name) { + ensureAttached(); return mBase.getRemotePreferences(name); } @NonNull @Override - public ApplicationInfo getApplicationInfo() { - return mBase.getApplicationInfo(); + public final ApplicationInfo getModuleApplicationInfo() { + ensureAttached(); + return mBase.getModuleApplicationInfo(); } @NonNull @Override - public String[] listRemoteFiles() { + public final String[] listRemoteFiles() { + ensureAttached(); return mBase.listRemoteFiles(); } @NonNull @Override - public ParcelFileDescriptor openRemoteFile(@NonNull String name) throws FileNotFoundException { + public final ParcelFileDescriptor openRemoteFile(@NonNull String name) throws FileNotFoundException { + ensureAttached(); return mBase.openRemoteFile(name); } } 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..cea5bbe 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; @@ -16,9 +17,9 @@ public interface XposedModuleInterface { */ interface ModuleLoadedParam { /** - * Gets information about whether the module is running in system server. + * Returns whether the current process is system server. * - * @return {@code true} if the module is running in system server + * @return {@code true} if the current process is system server */ boolean isSystemServer(); @@ -31,25 +32,12 @@ interface ModuleLoadedParam { String getProcessName(); } - /** - * Wraps information about system server. - */ - interface SystemServerLoadedParam { - /** - * Gets the class loader of system server. - * - * @return The class loader - */ - @NonNull - ClassLoader getClassLoader(); - } - /** * Wraps information about the package being loaded. */ interface PackageLoadedParam { /** - * Gets the package name of the package being loaded. + * Gets the package name of the current package. * * @return The package name. */ @@ -57,7 +45,7 @@ interface PackageLoadedParam { String getPackageName(); /** - * Gets the {@link ApplicationInfo} of the package being loaded. + * Gets the {@link ApplicationInfo} of the current package. * * @return The ApplicationInfo. */ @@ -65,44 +53,86 @@ interface PackageLoadedParam { ApplicationInfo getApplicationInfo(); /** - * Gets default class loader. + * Returns whether this is the first and main package loaded in the app process. * - * @return the default class loader + * @return {@code true} if this is the first package. + */ + boolean isFirstPackage(); + + /** + * Gets the default classloader of the current package. This is the classloader that loads + * the app's code, resources and custom {@link AppComponentFactory}. */ @RequiresApi(Build.VERSION_CODES.Q) @NonNull ClassLoader getDefaultClassLoader(); + } + /** + * Wraps information about the package whose classloader is ready. + */ + interface PackageReadyParam extends PackageLoadedParam { /** - * Gets the class loader of the package being loaded. - * - * @return The class loader. + * Gets the classloader of the current package. It may be different from {@link #getDefaultClassLoader()} + * if the package has a custom {@link android.app.AppComponentFactory} that creates a different classloader. */ @NonNull ClassLoader getClassLoader(); /** - * Gets information about whether is this package the first and main package of the app process. - * - * @return {@code true} if this is the first package. + * Gets the {@link AppComponentFactory} of the current package. */ - boolean isFirstPackage(); + @RequiresApi(Build.VERSION_CODES.P) + @NonNull + AppComponentFactory getAppComponentFactory(); + } + + /** + * Wraps information about system server. + */ + interface SystemServerStartingParam { + /** + * Gets the class loader of system server. + */ + @NonNull + ClassLoader getClassLoader(); } /** - * Gets notified when a package is loaded into the app process.
+ * Gets notified when the module is loaded into the target process.
+ * This callback is guaranteed to be called exactly once for a process. + * + * @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 is the time when the default + * classloader is ready but before the instantiation of custom {@link android.app.AppComponentFactory}.
* This callback could be invoked multiple times for the same process on each package. * * @param param Information about the package being loaded */ + @RequiresApi(Build.VERSION_CODES.Q) default void onPackageLoaded(@NonNull PackageLoadedParam param) { } /** - * Gets notified when the system server is loaded. + * Gets notified when custom {@link android.app.AppComponentFactory} has instantiated the app + * classloader and is ready to create {@link android.app.Activity} and {@link android.app.Service}.
+ * This callback could be invoked multiple times for the same process on each package. + * + * @param param Information about the package being loaded + */ + default void onPackageReady(@NonNull PackageReadyParam param) { + } + + /** + * Gets notified when system server is ready to start critical services. * * @param param Information about system server */ - default void onSystemServerLoaded(@NonNull SystemServerLoadedParam param) { + default void onSystemServerStarting(@NonNull SystemServerStartingParam param) { } } diff --git a/api/src/main/java/io/github/libxposed/api/errors/HookFailedError.java b/api/src/main/java/io/github/libxposed/api/error/HookFailedError.java similarity index 52% rename from api/src/main/java/io/github/libxposed/api/errors/HookFailedError.java rename to api/src/main/java/io/github/libxposed/api/error/HookFailedError.java index 0eb4b05..5e049ce 100644 --- a/api/src/main/java/io/github/libxposed/api/errors/HookFailedError.java +++ b/api/src/main/java/io/github/libxposed/api/error/HookFailedError.java @@ -1,7 +1,12 @@ -package io.github.libxposed.api.errors; +package io.github.libxposed.api.error; /** * Thrown to indicate that a hook failed due to framework internal error. + *

+ * Design Note: This inherits from {@link Error} rather than {@link RuntimeException} because hook failures are + * considered fatal framework bugs. Module developers should not attempt to catch this error to provide + * fallbacks. Instead, please report the issue to the framework maintainers so it can be fixed at the root. + *

*/ @SuppressWarnings("unused") public class HookFailedError extends XposedFrameworkError { diff --git a/api/src/main/java/io/github/libxposed/api/errors/XposedFrameworkError.java b/api/src/main/java/io/github/libxposed/api/error/XposedFrameworkError.java similarity index 90% rename from api/src/main/java/io/github/libxposed/api/errors/XposedFrameworkError.java rename to api/src/main/java/io/github/libxposed/api/error/XposedFrameworkError.java index 0b3bba0..39651e1 100644 --- a/api/src/main/java/io/github/libxposed/api/errors/XposedFrameworkError.java +++ b/api/src/main/java/io/github/libxposed/api/error/XposedFrameworkError.java @@ -1,4 +1,4 @@ -package io.github.libxposed.api.errors; +package io.github.libxposed.api.error; /** * Thrown to indicate that the Xposed framework function is broken. diff --git a/api/src/main/java/io/github/libxposed/api/utils/DexParser.java b/api/src/main/java/io/github/libxposed/api/utils/DexParser.java deleted file mode 100644 index 00a5f43..0000000 --- a/api/src/main/java/io/github/libxposed/api/utils/DexParser.java +++ /dev/null @@ -1,376 +0,0 @@ -package io.github.libxposed.api.utils; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.io.Closeable; - -/** - * Xposed interface for parsing dex files. - */ -@SuppressWarnings("unused") -public interface DexParser extends Closeable { - /** - * The constant NO_INDEX. - */ - int NO_INDEX = 0xffffffff; - - /** - * The interface Array. - */ - interface Array { - /** - * Get values value [ ]. - * - * @return the value [ ] - */ - @NonNull - Value[] getValues(); - } - - /** - * The interface Annotation. - */ - interface Annotation { - /** - * Gets visibility. - * - * @return the visibility - */ - int getVisibility(); - - /** - * Gets type. - * - * @return the type - */ - @NonNull - TypeId getType(); - - /** - * Get elements element [ ]. - * - * @return the element [ ] - */ - @NonNull - Element[] getElements(); - } - - /** - * The interface Value. - */ - interface Value { - - /** - * Get value byte [ ]. - * - * @return the byte [ ] - */ - @Nullable - byte[] getValue(); - - /** - * Gets value type. - * - * @return the value type - */ - int getValueType(); - } - - /** - * The interface Element. - */ - interface Element extends Value { - /** - * Gets name. - * - * @return the name - */ - @NonNull - StringId getName(); - } - /** - * The interface Id. - */ - interface Id extends Comparable { - /** - * Gets id. - * - * @return the id - */ - int getId(); - } - - /** - * The interface Type id. - */ - interface TypeId extends Id { - /** - * Gets descriptor. - * - * @return the descriptor - */ - @NonNull - StringId getDescriptor(); - } - - - /** - * The interface String id. - */ - interface StringId extends Id { - /** - * Gets string. - * - * @return the string - */ - @NonNull - String getString(); - } - - /** - * The interface Field id. - */ - interface FieldId extends Id { - /** - * Gets type. - * - * @return the type - */ - @NonNull - TypeId getType(); - - /** - * Gets declaring class. - * - * @return the declaring class - */ - @NonNull - TypeId getDeclaringClass(); - - /** - * Gets name. - * - * @return the name - */ - @NonNull - StringId getName(); - } - - /** - * The interface Method id. - */ - interface MethodId extends Id { - /** - * Gets declaring class. - * - * @return the declaring class - */ - @NonNull - TypeId getDeclaringClass(); - - /** - * Gets prototype. - * - * @return the prototype - */ - @NonNull - ProtoId getPrototype(); - - /** - * Gets name. - * - * @return the name - */ - @NonNull - StringId getName(); - } - - /** - * The interface Proto id. - */ - interface ProtoId extends Id { - /** - * Gets shorty. - * - * @return the shorty - */ - @NonNull - StringId getShorty(); - - /** - * Gets return type. - * - * @return the return type - */ - @NonNull - TypeId getReturnType(); - - /** - * Get parameters type id [ ]. - * - * @return the type id [ ] - */ - @Nullable - TypeId[] getParameters(); - } - - /** - * Get string id string id [ ]. - * - * @return the string id [ ] - */ - @NonNull - StringId[] getStringId(); - - /** - * Get type id type id [ ]. - * - * @return the type id [ ] - */ - @NonNull - TypeId[] getTypeId(); - - /** - * Get field id field id [ ]. - * - * @return the field id [ ] - */ - @NonNull - FieldId[] getFieldId(); - - /** - * Get method id method id [ ]. - * - * @return the method id [ ] - */ - @NonNull - MethodId[] getMethodId(); - - /** - * Get proto id proto id [ ]. - * - * @return the proto id [ ] - */ - @NonNull - ProtoId[] getProtoId(); - - /** - * Get annotations annotation [ ]. - * - * @return the annotation [ ] - */ - @NonNull - Annotation[] getAnnotations(); - - /** - * Get arrays array [ ]. - * - * @return the array [ ] - */ - @NonNull - Array[] getArrays(); - - /** - * The interface Early stop visitor. - */ - interface EarlyStopVisitor { - /** - * Stop boolean. - * - * @return the boolean - */ - boolean stop(); - } - - /** - * The interface Member visitor. - */ - interface MemberVisitor extends EarlyStopVisitor { - } - - /** - * The interface Class visitor. - */ - interface ClassVisitor extends EarlyStopVisitor { - /** - * Visit member visitor. - * - * @param clazz the clazz - * @param accessFlags the access flags - * @param superClass the super class - * @param interfaces the interfaces - * @param sourceFile the source file - * @param staticFields the static fields - * @param staticFieldsAccessFlags the static fields access flags - * @param instanceFields the instance fields - * @param instanceFieldsAccessFlags the instance fields access flags - * @param directMethods the direct methods - * @param directMethodsAccessFlags the direct methods access flags - * @param virtualMethods the virtual methods - * @param virtualMethodsAccessFlags the virtual methods access flags - * @param annotations the annotations - * @return the member visitor - */ - @Nullable - MemberVisitor visit(int clazz, int accessFlags, int superClass, @NonNull int[] interfaces, int sourceFile, @NonNull int[] staticFields, @NonNull int[] staticFieldsAccessFlags, @NonNull int[] instanceFields, @NonNull int[] instanceFieldsAccessFlags, @NonNull int[] directMethods, @NonNull int[] directMethodsAccessFlags, @NonNull int[] virtualMethods, @NonNull int[] virtualMethodsAccessFlags, @NonNull int[] annotations); - } - - /** - * The interface Field visitor. - */ - interface FieldVisitor extends MemberVisitor { - /** - * Visit. - * - * @param field the field - * @param accessFlags the access flags - * @param annotations the annotations - */ - void visit(int field, int accessFlags, @NonNull int[] annotations); - } - - /** - * The interface Method visitor. - */ - interface MethodVisitor extends MemberVisitor { - /** - * Visit method body visitor. - * - * @param method the method - * @param accessFlags the access flags - * @param hasBody the has body - * @param annotations the annotations - * @param parameterAnnotations the parameter annotations - * @return the method body visitor - */ - @Nullable - MethodBodyVisitor visit(int method, int accessFlags, boolean hasBody, @NonNull int[] annotations, @NonNull int[] parameterAnnotations); - } - - /** - * The interface Method body visitor. - */ - interface MethodBodyVisitor { - /** - * Visit. - * - * @param method the method - * @param accessFlags the access flags - * @param referredStrings the referred strings - * @param invokedMethods the invoked methods - * @param accessedFields the accessed fields - * @param assignedFields the assigned fields - * @param opcodes the opcodes - */ - void visit(int method, int accessFlags, @NonNull int[] referredStrings, @NonNull int[] invokedMethods, @NonNull int[] accessedFields, @NonNull int[] assignedFields, @NonNull byte[] opcodes); - } - - /** - * Visit defined classes. - * - * @param visitor the visitor - * @throws IllegalStateException the illegal state exception - */ - void visitDefinedClasses(@NonNull ClassVisitor visitor) throws IllegalStateException; -} diff --git a/checks/.gitignore b/checks/.gitignore deleted file mode 100644 index 42afabf..0000000 --- a/checks/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/checks/build.gradle.kts b/checks/build.gradle.kts deleted file mode 100644 index 1ac0040..0000000 --- a/checks/build.gradle.kts +++ /dev/null @@ -1,16 +0,0 @@ -plugins { - java - alias(libs.plugins.kotlin) -} - -java { - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 -} - -dependencies { - compileOnly(libs.lint.api) - compileOnly(libs.lint.checks) - compileOnly(libs.kotlin.stdlib) -} - diff --git a/checks/src/main/java/io/github/libxposed/lint/XposedIssueRegistry.kt b/checks/src/main/java/io/github/libxposed/lint/XposedIssueRegistry.kt deleted file mode 100644 index ec1d2b4..0000000 --- a/checks/src/main/java/io/github/libxposed/lint/XposedIssueRegistry.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.github.libxposed.lint - -import com.android.tools.lint.client.api.IssueRegistry -import com.android.tools.lint.detector.api.Issue - -class XposedIssueRegistry : IssueRegistry() { - override val issues: List - get() = emptyList() -} diff --git a/checks/src/main/resources/META-INF/services/com.android.tools.lint.client.api.IssueRegistry b/checks/src/main/resources/META-INF/services/com.android.tools.lint.client.api.IssueRegistry deleted file mode 100644 index fed5aa4..0000000 --- a/checks/src/main/resources/META-INF/services/com.android.tools.lint.client.api.IssueRegistry +++ /dev/null @@ -1 +0,0 @@ -io.github.libxposed.lint.XposedIssueRegistry diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7afe8af..5393904 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,15 +1,11 @@ [versions] annotation = "1.9.1" kotlin = "2.3.10" -lint = "32.0.1" agp = "9.0.1" [plugins] -kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } agp-lib = { id = "com.android.library", version.ref = "agp" } [libraries] annotation = { module = "androidx.annotation:annotation", version.ref = "annotation" } -lint-api = { module = "com.android.tools.lint:lint-api", version.ref = "lint" } -lint-checks = { module = "com.android.tools.lint:lint-checks", version.ref = "lint" } kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 23aa830..7e44cd3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -16,4 +16,4 @@ dependencyResolutionManagement { rootProject.name = "libxposed-api" -include(":api", ":checks") +include(":api")