Skip to content

Commit 5b5b414

Browse files
JingMatrixfatalcoder524
authored andcommitted
Invoke dexopt via command line (JingMatrix#445)
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.
1 parent 1dcbf52 commit 5b5b414

File tree

1 file changed

+42
-3
lines changed

1 file changed

+42
-3
lines changed

daemon/src/main/java/org/lsposed/lspd/service/PackageService.java

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@
5151

5252
import org.lsposed.lspd.models.Application;
5353

54+
import java.io.BufferedReader;
55+
import java.io.InputStreamReader;
5456
import java.lang.reflect.Constructor;
5557
import java.lang.reflect.InvocationTargetException;
5658
import java.util.ArrayList;
@@ -345,10 +347,47 @@ public static void clearApplicationProfileData(String packageName) throws Remote
345347
}
346348

347349
public static boolean performDexOptMode(String packageName) throws RemoteException {
348-
IPackageManager pm = getPackageManager();
349-
if (pm == null) return false;
350-
return pm.performDexOptMode(packageName,
350+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
351+
Process process = null;
352+
try {
353+
// The 'speed-profile' filter is a balanced choice for performance.
354+
String command = "cmd package compile -m speed-profile -f " + packageName;
355+
process = Runtime.getRuntime().exec(command);
356+
357+
// Capture and log the output for debugging.
358+
StringBuilder output = new StringBuilder();
359+
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
360+
String line;
361+
while ((line = reader.readLine()) != null) {
362+
output.append(line).append("\n");
363+
}
364+
}
365+
366+
int exitCode = process.waitFor();
367+
Log.i(TAG, "Dexopt command finished for " + packageName + " with exit code: " + exitCode);
368+
369+
// A successful command returns exit code 0 and typically "Success" in its output.
370+
return exitCode == 0 && output.toString().contains("Success");
371+
372+
} catch (Exception e) {
373+
Log.e(TAG, "Failed to execute dexopt shell command for " + packageName, e);
374+
if (e instanceof InterruptedException) {
375+
// Preserve the interrupted status.
376+
Thread.currentThread().interrupt();
377+
}
378+
return false;
379+
} finally {
380+
if (process != null) {
381+
process.destroy();
382+
}
383+
}
384+
} else {
385+
// Fallback to the original reflection method for older Android versions.
386+
IPackageManager pm = getPackageManager();
387+
if (pm == null) return false;
388+
return pm.performDexOptMode(packageName,
351389
SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false),
352390
SystemProperties.get("pm.dexopt.install", "speed-profile"), true, true, null);
391+
}
353392
}
354393
}

0 commit comments

Comments
 (0)