From bbada22cb329543c2fbb69f4d2b46d5b86872790 Mon Sep 17 00:00:00 2001
From: LoveSy Backed by the framework's dex query engine; {@link #query} returns an
+ * {@link android.database.Cursor} consumed like
+ * {@link android.database.sqlite.SQLiteDatabase#rawQuery}. Run as many queries as you like
+ * on one instance. The database holds native resources (the mapped dex/cache), so it is {@link Closeable} —
+ * {@link #close() close} it when done, ideally with try-with-resources. Closing the database
+ * does not close cursors already returned by {@link #query}; close those separately.
+ * After {@link #close()}, calling {@link #query} throws {@link IllegalStateException}. New features Backed by the framework's dex query engine; {@link #query} returns an
* {@link android.database.Cursor} consumed like
- * {@link android.database.sqlite.SQLiteDatabase#rawQuery}. Run as many queries as you like
- * on one instance.{@code
+ * // inside onPackageLoaded(PackageLoadedParam param):
+ * try (DexDatabase db = param.openDex();
+ * Cursor c = db.query("SELECT name FROM methods WHERE class = 'Lcom/foo/Bar;'")) {
+ * while (c.moveToNext()) {
+ * String name = c.getString(0);
+ * }
+ * }
+ * }
+ */
+@SinceApi(XposedInterface.API_103)
+public interface DexDatabase extends Closeable {
+ /**
+ * Runs a read-only SQL query against the dex.
+ *
+ * @param sql The SQL query; only {@code SELECT}-style reads are supported
+ * @return A {@link Cursor} over the result; close it when done
+ * @throws IllegalStateException If the database has been closed
+ */
+ @NonNull
+ Cursor query(@NonNull String sql);
+
+ /**
+ * Releases the native resources (mapped dex/cache) held by this database. Idempotent;
+ * does not affect cursors already returned by {@link #query}.
+ */
+ @Override
+ void close();
+}
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..bbefcde 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,21 @@ public interface XposedInterface {
*/
int API_102 = 102;
+ /**
+ * API version 103.
+ *
+ *
+ */
+ 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.
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 b07bc69..cdb969b 100644
--- a/api/src/main/java/io/github/libxposed/api/XposedModuleInterface.java
+++ b/api/src/main/java/io/github/libxposed/api/XposedModuleInterface.java
@@ -75,6 +75,20 @@ interface PackageLoadedParam {
@RequiresApi(Build.VERSION_CODES.Q)
@NonNull
ClassLoader getDefaultClassLoader();
+
+ /**
+ * Opens a read-only SQL view over this package's APK/DEX. The returned
+ * {@link DexDatabase} runs multiple {@link DexDatabase#query queries} and must be
+ * {@link DexDatabase#close() closed} when done (it holds the mapped dex/cache). The
+ * query is consumed like {@link android.database.sqlite.SQLiteDatabase#rawQuery}; only
+ * {@code SELECT}-style reads are supported.
+ *
+ * @return A {@link DexDatabase} over this package's dex; close it when done
+ * @throws UnsupportedOperationException If the framework does not support dex queries
+ */
+ @SinceApi(XposedInterface.API_103)
+ @NonNull
+ DexDatabase openDex();
}
/**
From 157366e110e58151368bf1a8cc3cb7dc9afcd66f Mon Sep 17 00:00:00 2001
From: Nullptr
The database holds native resources (the mapped dex/cache), so it is {@link Closeable} — * {@link #close() close} it when done, ideally with try-with-resources. Closing the database * does not close cursors already returned by {@link #query}; close those separately. * After {@link #close()}, calling {@link #query} throws {@link IllegalStateException}.
- * - *{@code
- * // inside onPackageLoaded(PackageLoadedParam param):
- * try (DexDatabase db = param.openDex();
- * Cursor c = db.query("SELECT name FROM methods WHERE class = 'Lcom/foo/Bar;'")) {
- * while (c.moveToNext()) {
- * String name = c.getString(0);
- * }
- * }
- * }
*/
@SinceApi(XposedInterface.API_103)
public interface DexDatabase extends Closeable {
@@ -39,7 +28,8 @@ public interface DexDatabase extends Closeable {
*
* @param sql The SQL query; only {@code SELECT}-style reads are supported
* @return A {@link Cursor} over the result; close it when done
- * @throws IllegalStateException If the database has been closed
+ * @throws IllegalArgumentException If the SQL is invalid or not a read-only query
+ * @throws IllegalStateException If the database has been closed
*/
@NonNull
Cursor query(@NonNull String sql);
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 bbefcde..a174a7d 100644
--- a/api/src/main/java/io/github/libxposed/api/XposedInterface.java
+++ b/api/src/main/java/io/github/libxposed/api/XposedInterface.java
@@ -12,6 +12,7 @@
import java.lang.reflect.Executable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
import java.util.List;
import io.github.libxposed.api.error.HookFailedError;
@@ -55,8 +56,9 @@ public interface XposedInterface {
* API version 103.
* New features
*The query covers dex sources owned directly by {@code classLoader}; parent class loaders + * are not included. Framework implementations should support common Android dex class loaders + * such as {@link dalvik.system.PathClassLoader}, {@link dalvik.system.DexClassLoader}, + * {@link dalvik.system.DelegateLastClassLoader}, and + * {@link dalvik.system.InMemoryDexClassLoader}.
+ * + *This method must not load classes from {@code classLoader}. The returned + * {@link DexDatabase} owns the mapped dex/cache resources until + * {@link DexDatabase#close() closed}; closing the database does not affect the class loader.
+ * + * @param classLoader The class loader whose dex sources should be queried + * @return A {@link DexDatabase} over the class loader's dex sources; close it when done + * @throws IllegalArgumentException If {@code classLoader} is not a supported dex class + * loader or does not contain supported dex content + */ + @SinceApi(API_103) + @NonNull + DexDatabase openDex(@NonNull ClassLoader classLoader); + + /** + * Opens a read-only SQL view over in-memory APK/JAR/DEX data. + * + *Each source may contain a raw {@code .dex} file or a zip-based container such as an + * APK/JAR containing {@code classes*.dex} entries.
+ * + *For each buffer, the bytes between its current {@link ByteBuffer#position() position} and + * {@link ByteBuffer#limit() limit} are used. This method must not change the buffer's + * position, limit, or mark. Heap, direct, mapped, and read-only buffers are all valid. + * Framework implementations may retain the supplied buffers until the returned + * {@link DexDatabase} is {@link DexDatabase#close() closed}; callers must not mutate the + * remaining bytes or their backing storage before then.
+ * + * @param sources One or more buffers containing APK/JAR/DEX data + * @return A {@link DexDatabase} over the supplied sources; close it when done + * @throws IllegalArgumentException If {@code sources} is empty, contains {@code null}, or + * does not contain supported dex content + */ + @SinceApi(API_103) + @NonNull + DexDatabase openDex(@NonNull ByteBuffer... sources); + /** * Get a method invoker for the given method. Invocations through invokers will bypass access * checks. The default type of the invoker is {@link Invoker.Type.Chain#FULL}. 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..ddf49b5 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java +++ b/api/src/main/java/io/github/libxposed/api/XposedInterfaceWrapper.java @@ -11,6 +11,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Method; +import java.nio.ByteBuffer; import io.github.libxposed.annotation.InternalApi; import io.github.libxposed.annotation.SinceApi; @@ -136,6 +137,22 @@ public final boolean deoptimize(@NonNull Executable executable) { return mBase.deoptimize(executable); } + @SinceApi(API_103) + @NonNull + @Override + public final DexDatabase openDex(@NonNull ClassLoader classLoader) { + ensureAttached(); + return mBase.openDex(classLoader); + } + + @SinceApi(API_103) + @NonNull + @Override + public final DexDatabase openDex(@NonNull ByteBuffer... sources) { + ensureAttached(); + return mBase.openDex(sources); + } + @NonNull @Override public final Invoker, Method> getInvoker(@NonNull Method method) { 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 cdb969b..b07bc69 100644 --- a/api/src/main/java/io/github/libxposed/api/XposedModuleInterface.java +++ b/api/src/main/java/io/github/libxposed/api/XposedModuleInterface.java @@ -75,20 +75,6 @@ interface PackageLoadedParam { @RequiresApi(Build.VERSION_CODES.Q) @NonNull ClassLoader getDefaultClassLoader(); - - /** - * Opens a read-only SQL view over this package's APK/DEX. The returned - * {@link DexDatabase} runs multiple {@link DexDatabase#query queries} and must be - * {@link DexDatabase#close() closed} when done (it holds the mapped dex/cache). The - * query is consumed like {@link android.database.sqlite.SQLiteDatabase#rawQuery}; only - * {@code SELECT}-style reads are supported. - * - * @return A {@link DexDatabase} over this package's dex; close it when done - * @throws UnsupportedOperationException If the framework does not support dex queries - */ - @SinceApi(XposedInterface.API_103) - @NonNull - DexDatabase openDex(); } /**