diff --git a/README.md b/README.md index 081f36b..b3009fc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # libxposed API -[![API](https://img.shields.io/badge/API-102-brightgreen)](https://github.com/libxposed/api) +[![API](https://img.shields.io/badge/API-103-brightgreen)](https://github.com/libxposed/api) [![Maven Central](https://img.shields.io/maven-central/v/io.github.libxposed/api?color=blue)](https://central.sonatype.com/artifact/io.github.libxposed/api) [![Android Min SDK](https://img.shields.io/badge/minSdk-26-orange)](https://developer.android.com/about/versions/oreo) [![License](https://img.shields.io/github/license/libxposed/api)](LICENSE) @@ -13,7 +13,7 @@ Modern Xposed Module API — a type-safe, redesigned replacement for the legacy ```kotlin dependencies { - compileOnly("io.github.libxposed:api:102.0.0") + compileOnly("io.github.libxposed:api:103.0.0") } ``` @@ -33,7 +33,7 @@ These rules keep module entry classes from being removed and rewrite `META-INF/x ```kotlin dependencies { - implementation("io.github.libxposed:api:102.0.0") + implementation("io.github.libxposed:api:103.0.0") } ``` diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 8f9ea18..79b4893 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -32,7 +32,7 @@ android { } } -val libVersion = "102.0.0" +val libVersion = "103.0.0" val publishSnapshot = providers.gradleProperty("publishSnapshot").orNull == "true" val dependencySnapshot = providers.gradleProperty("dependencySnapshot").orNull == "true" fun String.real(snapshot: Boolean) = if (snapshot) "$this-SNAPSHOT" else this 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 c36b775..4a15c76 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedInterface.java +++ b/api/src/main/java/io/github/libxposed/api/XposedInterface.java @@ -51,11 +51,20 @@ public interface XposedInterface { */ int API_102 = 102; + /** + * API version 103. + *

New features

+ * + */ + int API_103 = 103; + /** * 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 LIB_API = API_102; + int LIB_API = API_103; /** * The framework has the capability to hook system_server and other system processes. @@ -507,6 +516,47 @@ default int getApiVersion() { @NonNull CtorInvoker getInvoker(@NonNull Constructor constructor); + /** + * Scans the Java heap for live objects matching the supplied class. + * + *

This can be used to obtain already-created target objects directly instead of installing nested hooks + * only to capture them from later calls.

+ * + *

Returned object references are strong references. Keeping the returned results reachable also keeps + * returned objects reachable.

+ * + *

The framework does not run a garbage collection before scanning. Non-reachable but not-yet-collected objects + * will be returned as well. If you need to exclude objects that are only waiting to be collected, you should trigger + * garbage collection before calling this method.

+ * + *

The overload of scanning one class is the same as scanning multiple classes with the batched API. + * If you need to scan multiple classes, it is recommended to use the batched API to reduce the number + * of heap walks and improve performance.

+ * + * @param clazz The class to match. Primitive classes and {@code void.class} are not valid. + * @param assignable Whether to match subclasses of the class. + * @param The expected type of matching objects + * @return An array of matching objects. The array is empty if no matching objects are found. + * @throws IllegalArgumentException if the class is primitive or void + */ + @SinceApi(API_103) + @NonNull + T[] findInstances(@NonNull Class clazz, boolean assignable); + + /** + * Scans the Java heap for live objects matching the supplied classes. + * + * @param classes The classes to match. Primitive classes and {@code void.class} are not valid. + * @param assignable Whether to match subclasses of the classes. + * @return An array of arrays of matching objects. Each inner array corresponds to the matching objects for the class + * at the same index in the input array. The inner arrays are empty if no matching objects are found for that class. + * @throws IllegalArgumentException if any class is primitive, void or null + * @see #findInstances(Class, boolean) + */ + @SinceApi(API_103) + @NonNull + Object[][] findInstances(@NonNull Class[] classes, boolean assignable); + /** * Writes a message to the Xposed log. * 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 fdfc9ae..2d0085e 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java +++ b/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java @@ -150,6 +150,20 @@ public final CtorInvoker getInvoker(@NonNull Constructor constructor) return mBase.getInvoker(constructor); } + @NonNull + @Override + public T[] findInstances(@NonNull Class clazz, boolean assignable) { + ensureAttached(); + return mBase.findInstances(clazz, assignable); + } + + @NonNull + @Override + public Object[][] findInstances(@NonNull Class[] classes, boolean assignable) { + ensureAttached(); + return mBase.findInstances(classes, assignable); + } + @Override public final void log(int priority, @Nullable String tag, @NonNull String msg) { ensureAttached(); diff --git a/api/src/main/java/io/github/libxposed/api/package-info.java b/api/src/main/java/io/github/libxposed/api/package-info.java index 74a07ca..4bd4036 100644 --- a/api/src/main/java/io/github/libxposed/api/package-info.java +++ b/api/src/main/java/io/github/libxposed/api/package-info.java @@ -97,6 +97,15 @@ * getInvoker(Constructor)}. The invoker type controls what part of the hook chain is executed * (see {@link io.github.libxposed.api.XposedInterface.Invoker.Type Invoker.Type}).

* + *

Object Scanning (API 103+)

+ * + *

Find already-created objects by class with + * {@link io.github.libxposed.api.XposedInterface#findInstances(java.lang.Class, boolean)} or + * {@link io.github.libxposed.api.XposedInterface#findInstances(java.lang.Class[], boolean)}. + * This is useful when a module needs a target object that may already exist before its hooks are + * installed, avoiding extra nested hooks whose only purpose is to capture that object from later + * calls.

+ * *

Module Lifecycle Callbacks

* *

Override the following callbacks in {@link io.github.libxposed.api.XposedModule}: