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

  1. Retry the dex2oat compilation on a non-interrupted thread after verifying shutdown is not in progress
  2. Check for code paths that call Thread.interrupt() on the compiling thread and fix the premature cancellation
  3. Ensure dex2oat runs on a dedicated background thread that is not interrupted during app lifecycle events
  4. 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

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


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)