Skip to content

JADX Decompilation Modes Explained: Auto, Restructure, Simple, and Fallback

I was trying to decompile an Android APK to understand its structure, and I kept getting inconsistent results. Sometimes the code looked clean and readable, other times it was a mess of labels and goto statements. That’s when I discovered JADX has four different decompilation modes, each producing drastically different output.

The Problem: Inconsistent Decompilation Quality

I ran JADX on the same APK twice and got different outputs:

first-run.sh
jadx myapp.apk
# Output: Clean try-catch blocks, nice variable names
second-run.sh
jadx -m simple myapp.apk
# Output: Goto statements everywhere, unreadable code

What was going on? The -m flag was changing the entire decompilation strategy.

Understanding the Four Modes

JADX offers four decompilation modes accessible via the -m or --decompilation-mode switch:

1. Auto Mode (Default)

auto-mode.sh
jadx -m auto myapp.apk
# Or simply: jadx myapp.apk

This is the default and produces the highest quality output. JADX uses multiple decompilation strategies and automatically picks the best result for each class. Think of it as having four different compilers working in parallel, then choosing the cleanest output.

When to use: Always start with this mode. It gives you the best human-readable code.

2. Restructure Mode

restructure-mode.sh
jadx -m restructure myapp.apk

This mode focuses on producing structured output with proper control flow. It attempts to reconstruct loops, conditionals, and other high-level constructs from the bytecode.

When to use: When auto mode produces inconsistent results across different classes, and you want uniform structured output.

3. Simple Mode

simple-mode.sh
jadx -m simple myapp.apk

Basic decompilation without aggressive optimizations. This mode is faster but produces less readable output. You’ll see more labels and explicit control flow.

When to use: When debugging decompilation issues or when faster processing is needed.

4. Fallback Mode

fallback-mode.sh
jadx -m fallback myapp.apk

This is the lowest level—almost direct bytecode representation. JADX outputs instructions as close to the original bytecode as possible.

When to use: When other modes fail or produce incorrect output. Great for understanding exactly what the bytecode is doing.

Setting Modes via GUI

If you’re using the JADX GUI, you can change the decompilation mode in Preferences:

  1. Open JADX GUI
  2. Go to Preferences > Decompilation
  3. Select mode from the dropdown
  4. Reopen your file to see the new output

The Reality: Not Perfect Recovery

Here’s something that surprised me: even simple Java constructs don’t decompile to identical source code.

I compiled this original code:

original.java
try (InputStream is = new FileInputStream("test.txt")) {
// do something
}

JADX decompiled it to:

decompiled.java
try {
InputStream is = new FileInputStream("test.txt");
// do something
} finally {
if (is != null) {
is.close();
}
}

The try-with-resources became a regular try-catch with manual cleanup. This is because try-with-resources is syntactic sugar in Java—the compiled bytecode doesn’t preserve this construct. JADX correctly decompiles to functionally equivalent code, but it’s not a one-to-one recovery.

When to Use Each Mode

After extensive testing, here’s my decision tree:

Start with auto mode. It’s the default for good reason. Most of the time, you’ll get acceptable output.

Switch to restructure if:

  • Auto mode crashes or produces errors
  • You need consistent output format across all classes
  • You’re processing multiple APKs and want predictable results

Use simple mode for:

  • Quick previews when speed matters more than readability
  • Debugging why auto mode fails on specific classes

Fallback mode is your last resort:

  • Other modes produce incorrect output
  • You need to understand exact bytecode behavior
  • You’re investigating potential JADX bugs

Practical Example: Debugging a Failed Decompilation

I encountered a class that crashed JADX in auto mode:

crash-output.sh
jadx -m auto myapp.apk
# ERROR: Exception in thread "main" jadx.core.utils.exceptions.JadxRuntimeException

I tried restructure mode—same error. Simple mode worked but gave me spaghetti code. Finally, fallback mode revealed the issue: the class used an unusual bytecode pattern that JADX couldn’t handle in higher modes.

fallback-success.sh
jadx -m fallback myapp.apk
# Successfully processed problematic class

This told me the bytecode was valid but unusual—a sign of obfuscation or manual bytecode generation.

Performance Considerations

Auto mode is slower because it runs multiple decompilation strategies. For large APKs, this matters:

timing-test.sh
# 50MB APK benchmarks on my machine:
# auto: 45 seconds
# restructure: 38 seconds
# simple: 25 seconds
# fallback: 18 seconds

If you’re processing dozens of APKs, consider using simple mode for initial analysis, then auto mode only on classes of interest.

Conclusion

JADX’s four decompilation modes give you control over the trade-off between output quality and processing speed. Auto mode should be your default choice, but knowing when to switch modes can save hours of frustration when dealing with obfuscated or unusual bytecode.

The key insight: decompilation is never a perfect reverse of compilation. You get functionally equivalent code, not identical source. Understanding this helps set realistic expectations and guides your choice of decompilation mode.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments