asLody/VirtualApp · error · IOException
dex2oat is interrupted, msg
Error message
dex2oat is interrupted, msg: ${e.getMessage()} What it means
interpretDex2Oat runs the dex2oat binary as a child process to compile an APK's DEX to OAT. If the thread waiting for the process is interrupted, waitFor() throws InterruptedException, which is rethrown as an IOException with this message. It signals the optimization was cancelled mid-run, usually by shutdown or another failure upstream.
Solutions
- Retry the dex2oat compilation on a non-interrupted thread after verifying shutdown is not in progress
- Check for code paths that call Thread.interrupt() on the compiling thread and fix the premature cancellation
- Ensure dex2oat runs on a dedicated background thread that is not interrupted during app lifecycle events
- Clear the interrupt flag (Thread.interrupted()) only if cancellation is stale, then retry once
Example fix
// before
try {
final int ret = dex2oatProcess.waitFor();
} catch (InterruptedException e) {
throw new IOException("dex2oat is interrupted, msg: " + e.getMessage(), e);
}
// after
try {
final int ret = dex2oatProcess.waitFor();
} catch (InterruptedException e) {
if (!shuttingDown) {
Thread.currentThread().interrupt();
final int ret = dex2oatProcess.waitFor(); // retry on a non-cancelled path
} else {
throw new IOException("dex2oat is interrupted, msg: " + e.getMessage(), e);
}
} Defensive patterns
Strategy: try-catch
Validate before calling
if (Thread.currentThread().isInterrupted()) {
// reschedule compilation instead of starting it
return;
} Try / catch
try {
ArtDexOptimizer.compileDex(...);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().contains("interrupted")) {
Thread.currentThread().interrupt();
// retry later or degrade to interpreter mode
}
} Prevention
- Run dex2oat on a dedicated long-lived worker thread
- Do not interrupt threads during app shutdown without awaiting completion
- Treat the IOException-with-'interrupted' message as a cancellation signal
When it happens
Trigger: Calling ArtDexOptimizer.compileDex/interpretDex2Oat while the calling thread is interrupted (e.g. during executor shutdown, activity destroy, or process teardown), causing dex2oatProcess.waitFor() to throw InterruptedException.
Common situations: App closing or virtual process being killed while background compilation is still running; cancelling a parallel optimize task; timeouts implemented by interrupting worker threads.
Related errors
- dex2oat works unsuccessfully, exit code
- Unable to create application
- Unable to start receiver
- VirtualCore.startup() must called in main thread.
- Initializer = NULL
AI-assisted analysis of asLody/VirtualApp@666fefcb5d (2026-09-09).
Data as JSON: /api/errors/217fe6fe33eee33d.
Report an issue: GitHub.
Appendix: source
Thrown at VirtualApp/lib/src/main/java/com/lody/virtual/helper/ArtDexOptimizer.java:62
commandAndParams.add("--instruction-set=" + VMRuntime.getCurrentInstructionSet.call());
if (Build.VERSION.SDK_INT > 25) {
commandAndParams.add("--compiler-filter=quicken");
} else {
commandAndParams.add("--compiler-filter=interpret-only");
}
final ProcessBuilder pb = new ProcessBuilder(commandAndParams);
pb.redirectErrorStream(true);
final Process dex2oatProcess = pb.start();
StreamConsumer.consumeInputStream(dex2oatProcess.getInputStream());
StreamConsumer.consumeInputStream(dex2oatProcess.getErrorStream());
try {
final int ret = dex2oatProcess.waitFor();
if (ret != 0) {
throw new IOException("dex2oat works unsuccessfully, exit code: " + ret);
}
} catch (InterruptedException e) {
throw new IOException("dex2oat is interrupted, msg: " + e.getMessage(), e);
}
}
private static class StreamConsumer {
static final Executor STREAM_CONSUMER = Executors.newSingleThreadExecutor();
static void consumeInputStream(final InputStream is) {
STREAM_CONSUMER.execute(new Runnable() {
@Override
public void run() {
if (is == null) {
return;
}
final byte[] buffer = new byte[256];
try {
while ((is.read(buffer)) > 0) {
// To satisfy checkstyle rules.
}View on GitHub (pinned to 666fefcb5d)