Why Android Cannot Run Standard Java: Inside the art/ Directory
Mobile devices live under extreme constraints. Standard Java Virtual Machines assume continuous wall power and gigabytes of memory. A smartphone running on a small battery cannot afford the constant CPU overhead of interpreting bytecode. The operating system needs an execution environment built specifically for limited resources.
This custom environment lives entirely inside the art/ directory. The Android Runtime (ART) is the highly optimized engine responsible for executing all application code. Instead of standard Java class files, ART executes specialized Dalvik bytecode packaged as .dex files. It manages memory allocation, garbage collection, and the core libraries that provide primitive functions.
To balance fast startup times with battery efficiency, ART employs a hybrid compilation strategy. Just-In-Time (JIT) compilation translates code on the fly when the user first opens an application. Ahead-of-Time (AOT) compilation translates the bytecode into native machine instructions while the device is plugged in and idle. Think of ART as a bilingual translator. JIT is translating a speech live as it happens, which creates some mental overhead. AOT is translating a whole book before publishing it, which takes longer upfront but makes reading incredibly fast.
The compilation lifecycle transforms raw source code into hardware instructions through a clear three-step path. First, the build system converts human-readable source code into DEX bytecode. Second, the application is packaged and installed onto the device hardware. Third, the compiler generates the final optimized machine code for execution.
This pipeline ensures that every application runs as efficiently as possible on the specific CPU architecture. The process reduces battery drain during heavy application usage.
Developers occasionally need to measure how an application performs after a full installation. You can force the device to compile an application immediately using a specific shell command.
adb shell cmd package compile -m speed -f com.example.myapp
The most common mistake engineers make with this command is forgetting to clear the existing profile data first, which leads to inconsistent profiling results.
Warning: Do not modify ART source unless you are an expert compiler engineer. A tiny error will crash every app on the system.
ART keeps our applications running smoothly by tuning garbage collection for UI fluidity. Now that we know how the OS executes our app's code, we need to look at where the platform gets standard tools like databases and web renderers without rewriting them from scratch.
How AOSP Integrates Open Source: The external/ Directory
Writing a secure cryptography library takes years of specialized engineering. Building a fully compliant web rendering engine takes even longer. An operating system built entirely from scratch would take decades to finish. The Android team solves this by incorporating mature open-source projects into the platform.
The external/ directory holds all the third-party source code that Android relies on. This directory functions similarly to a package manager dependency block. Instead of reinventing the wheel, Google imports massive external projects like SQLite, Chromium, and BoringSSL. The AOSP build system then compiles these external repositories right alongside the native platform code.
To make an upstream project compatible with the Android build system, Google engineers add a build file to the root of the imported repository. This file tells the build system exactly how to compile the external code into a shared library. The Android framework can then link against this compiled library natively.
We can trace this integration process from an upstream repository down to a usable Android library in three steps. First, Google imports the raw upstream source code into the external directory. Second, engineers create build rules to translate the code for the Android platform. Third, the build system outputs a native shared library file for the framework to use.
Original upstream source code remains untouched while the build file acts as the bridge. The resulting native file is what the rest of the operating system actually calls during runtime.
Tracing a database query reveals this exact structure in action. When a Java application calls the android.database.sqlite framework package, the system accesses native C++ code in frameworks/base/core/jni via JNI. That native code links directly against the C implementation living inside the external/sqlite directory.
Tip: If you find a bug in
external/sqlite, you should look to see if the upstream SQLite project has patched it rather than trying to fix it in AOSP directly.
Our tour of the runtime and external libraries is complete. There is one final piece of the OS puzzle left, which involves the code that runs when the main OS is offline for maintenance.
Life Before the System Server: Inside bootable/
You cannot overwrite an operating system partition while the system is actively running from it. The kernel locks the active file system to prevent catastrophic corruption. Installing an OTA update or performing a factory reset requires the device to boot into an entirely separate environment.
The bootable/ directory provides the source code for this secondary environment. Android Recovery Mode is a minimalist Linux distribution designed exclusively for safe disk operations. When the device enters recovery mode, the main Android OS remains completely powered down. The recovery environment can then safely mount, wipe, and reflash the system partitions.
When a user taps the button to install an update, the system writes a special command flag to the cache partition. The device then reboots immediately. The bootloader detects this flag and redirects the boot sequence to the recovery partition instead of the primary system partition. Recovery reads the update package, applies the changes, and initiates a normal reboot.
The boot process diverges based on the presence of the cache flag through a precise three-step sequence. First, the bootloader reads the hardware state and checks for the update flag. Second, if the flag exists, the device launches the recovery environment to apply changes. Third, once the flashing completes, the device restarts back into the normal operating system.
This routing decision relies entirely on a simple text file. Once the recovery environment finishes its job, the standard boot sequence resumes.
Did You Know: You will not find the actual bootloader for a modern Pixel or Samsung device in the
bootable/directory. AOSP used to include open-source reference bootloaders like Little Kernel (lk), but today's secure boot chains mean silicon vendors keep their bootloaders completely proprietary and closed-source.
Our journey through the source tree has uncovered millions of lines of code spanning custom runtime environments, integrated open-source giants, and bare-metal recovery systems. We spent the last several articles looking at the source code at rest. But code at rest doesn't run a phone. In the next module, we will invoke the Soong build system and watch how AOSP transforms from 250GB of text files into a bootable Android image.