From 0df8fcd64ffd4ad0cda1060f555329b61e3d6ea3 Mon Sep 17 00:00:00 2001 From: JingMatrix Date: Sat, 4 Oct 2025 12:30:35 +0200 Subject: [PATCH] Invoke dexopt via command line Starting with Android 14 (API level 34), the Android Runtime (ART) Service handles on-device Ahead-Of-Time (AOT) compilation, also known as `dexopt`. As a result, in Android 16 beta qpr2, the method `performDexOptMode` is removed. See https://source.android.com/docs/core/runtime/configure/package-manager for details. --- .../lsposed/lspd/service/PackageService.java | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/daemon/src/main/java/org/lsposed/lspd/service/PackageService.java b/daemon/src/main/java/org/lsposed/lspd/service/PackageService.java index a0a356708..ec967d9f1 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/PackageService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/PackageService.java @@ -51,6 +51,8 @@ import org.lsposed.lspd.models.Application; +import java.io.BufferedReader; +import java.io.InputStreamReader; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; @@ -345,10 +347,47 @@ public static void clearApplicationProfileData(String packageName) throws Remote } public static boolean performDexOptMode(String packageName) throws RemoteException { - IPackageManager pm = getPackageManager(); - if (pm == null) return false; - return pm.performDexOptMode(packageName, + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + Process process = null; + try { + // The 'speed-profile' filter is a balanced choice for performance. + String command = "cmd package compile -m speed-profile -f " + packageName; + process = Runtime.getRuntime().exec(command); + + // Capture and log the output for debugging. + StringBuilder output = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + String line; + while ((line = reader.readLine()) != null) { + output.append(line).append("\n"); + } + } + + int exitCode = process.waitFor(); + Log.i(TAG, "Dexopt command finished for " + packageName + " with exit code: " + exitCode); + + // A successful command returns exit code 0 and typically "Success" in its output. + return exitCode == 0 && output.toString().contains("Success"); + + } catch (Exception e) { + Log.e(TAG, "Failed to execute dexopt shell command for " + packageName, e); + if (e instanceof InterruptedException) { + // Preserve the interrupted status. + Thread.currentThread().interrupt(); + } + return false; + } finally { + if (process != null) { + process.destroy(); + } + } + } else { + // Fallback to the original reflection method for older Android versions. + IPackageManager pm = getPackageManager(); + if (pm == null) return false; + return pm.performDexOptMode(packageName, SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false), SystemProperties.get("pm.dexopt.install", "speed-profile"), true, true, null); + } } }