Introduction to PREEMPT_RT and Real-Time Android
The Linux kernel’s PREEMPT_RT patchset transforms a general-purpose operating system into one capable of handling real-time workloads with significantly reduced latency and improved determinism. For Android, this translates to tangible benefits in applications requiring precise timing, such as industrial control, robotics, high-performance audio/video processing, and even advanced gaming. Integrating PREEMPT_RT into an Android kernel, however, typically involves a complex, multi-step manual process that can be error-prone and time-consuming, hindering rapid development and iteration.
This article provides an expert-level guide to automating the entire workflow: from fetching the kernel source and applying PREEMPT_RT patches, through compiling the kernel and its modules, to finally flashing it onto an Android device. By leveraging a robust shell script, developers can streamline their real-time Android kernel development cycles, ensuring consistency and efficiency.
Prerequisites and Environment Setup
Before diving into automation, ensure your development environment is correctly configured. You’ll need:
- A Linux-based host machine (Ubuntu, Debian, Fedora recommended).
- Sufficient disk space (at least 50GB) and RAM (16GB+) for kernel compilation.
- The Android SDK Platform-Tools (
adbandfastboot) installed and in your PATH. - A cross-compilation toolchain for ARM64 (AArch64) or ARM (depending on your device). Google’s official Android NDK toolchain is recommended.
- The kernel source code for your specific Android device. Obtain this from your device manufacturer’s open-source repositories or the AOSP common kernels.
- Git for version control and patch management.
Setting Up the Toolchain
Download the NDK and extract it. Then, set environment variables:
export NDK_ROOT=/path/to/android-ndk-r25c # Adjust to your NDK version
export PATH=$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
export CROSS_COMPILE=$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-
export ARCH=arm64
Replace aarch64-linux-android- with arm-linux-androideabi- if targeting 32-bit ARM.
Step-by-Step Automation Script Development
Let’s construct a bash script, build_and_flash_rt.sh, that encapsulates the entire process.
1. Initial Setup and Variables
Define essential paths and filenames at the beginning of your script.
#!/bin/bash
# --- Configuration Variables ---
KERNEL_DIR="$(pwd)/android-kernel"
RT_PATCH_VERSION="6.1.72-rt20" # Match your kernel version
DEVICE_CODENAME="trout" # Example: Pixel 6a
FASTBOOT_IMAGE_NAME="Image" # Often 'Image' or 'Image.gz-dtb'
BOOT_IMG_TOOLS_DIR="$(pwd)/android-bootimg-tools" # If creating boot.img
# Toolchain variables (ensure these match your environment)
export NDK_ROOT="/path/to/android-ndk-r25c"
export PATH="$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH"
export CROSS_COMPILE="$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-"
export ARCH="arm64"
# Kernel configuration
DEFCONFIG="gki_defconfig" # Common for AOSP GKI kernels
MAKE_JOBS=$(nproc)
# --- Functions for logging ---
log_info() { echo -e "
[INFO] $1
"; }
log_error() { echo -e "
[ERROR] $1
" >&2; exit 1; }
log_success() { echo -e "
[SUCCESS] $1
"; }
2. Fetching Kernel Source and PREEMPT_RT Patches
The script should clone your kernel source and download the appropriate PREEMPT_RT patch.
# --- Step 1: Clone Kernel Source ---
if [ ! -d "$KERNEL_DIR" ]; then
log_info "Cloning kernel source for $DEVICE_CODENAME..."
# Replace with your actual kernel source URL
git clone https://android.googlesource.com/kernel/common.git "$KERNEL_DIR"
cd "$KERNEL_DIR"
git checkout android-6.1-r-gsi # Or your specific branch/tag
cd ..
else
log_info "Kernel directory $KERNEL_DIR already exists. Skipping clone."
cd "$KERNEL_DIR"
git reset --hard
git clean -fdx
git pull
cd ..
fi
# --- Step 2: Download and Apply PREEMPT_RT Patch ---
log_info "Downloading PREEMPT_RT patch $RT_PATCH_VERSION..."
RT_PATCH_FILE="patch-${RT_PATCH_VERSION}.patch.gz"
wget -nc https://www.kernel.org/pub/linux/kernel/projects/rt/6.1/older/"$RT_PATCH_FILE" || log_error "Failed to download RT patch."
log_info "Applying PREEMPT_RT patch..."
gunzip -c "$RT_PATCH_FILE" | patch -d "$KERNEL_DIR" -p1 || log_error "Failed to apply RT patch."
3. Kernel Configuration for Real-Time
Navigate into the kernel directory and configure it. You’ll need to enable PREEMPT_RT features.
# --- Step 3: Configure Kernel ---
log_info "Entering kernel directory $KERNEL_DIR..."
cd "$KERNEL_DIR" || log_error "Could not enter kernel directory."
log_info "Generating default config from $DEFCONFIG..."
make $DEFCONFIG || log_error "Failed to generate default config."
log_info "Enabling PREEMPT_RT features in .config..."
# Use scripts/config for robust modification
./scripts/config --file .config -e PREEMPT_RT_BASE
./scripts/config --file .config -e PREEMPT_RT_FULL
./scripts/config --file .config -d PREEMPT_VOLUNTARY
# You might need to disable some modules that conflict or aren't needed
# Example: ./scripts/config --file .config -d BT_LE_LL_PRIVACY
log_info "Updating kernel config with menuconfig... (manual step, save & exit)"
make menuconfig # IMPORTANT: Manually review and save config. Ensure PREEMPT_RT_FULL is selected.
# Press 'Y' for full preemption. Exit and save.
# If running headless, consider a pre-baked .config file.
log_info "Old defconfig generation from current .config for future use..."
make savedefconfig
cp defconfig arch/$ARCH/configs/${DEFCONFIG}_rt || log_error "Failed to save RT defconfig."
The make menuconfig step is crucial. For full automation, you might pre-configure a .config file with all RT options enabled and copy it into place, replacing make menuconfig with cp my_rt_config .config.
4. Building the Kernel and Modules
Compile the kernel image and its modules.
# --- Step 4: Build Kernel ---
log_info "Building kernel Image and modules (using $MAKE_JOBS jobs)..."
make -j$MAKE_JOBS || log_error "Kernel build failed."
make modules_install INSTALL_MOD_PATH="$(pwd)/modules_install" || log_error "Modules install failed."
# Assuming kernel image is in arch/arm64/boot/
KERNEL_IMAGE_PATH="arch/$ARCH/boot/$FASTBOOT_IMAGE_NAME"
if [ ! -f "$KERNEL_IMAGE_PATH" ]; then
log_error "Kernel image not found at $KERNEL_IMAGE_PATH."
fi
log_success "Kernel build completed: $KERNEL_IMAGE_PATH"
5. Flashing the Kernel to the Device
This step assumes you have fastboot access and your device is in bootloader mode. For Android kernels, you often flash a boot.img or just the kernel image itself depending on your device’s architecture and bootloader. Some devices require manual creation of boot.img using tools like mkbootimg, while others accept a direct fastboot flash boot_a Image.
# --- Step 5: Flash Kernel to Device ---
log_info "Attempting to flash kernel to device... Ensure device is in fastboot mode."
# Example for devices that accept direct Image flashing (like some AOSP GKI variants)
# This is often 'boot_a' or 'boot_b' on A/B partitioned devices.
# Adjust based on your device's partitioning scheme and fastboot commands.
fastboot flash boot_a "$KERNEL_IMAGE_PATH" || log_error "Fastboot flash failed. Is device in bootloader?"
# If you need to create a boot.img, uncomment and adjust these lines:
# log_info "Creating boot.img..."
# if [ ! -d "$BOOT_IMG_TOOLS_DIR" ]; then
# log_error "Boot image tools not found at $BOOT_IMG_TOOLS_DIR."
# fi
# # Example: mkbootimg --kernel "$KERNEL_IMAGE_PATH" --ramdisk path/to/ramdisk.img --base 0x40000000 --pagesize 4096 -o new_boot.img
# # fastboot flash boot new_boot.img
log_info "Rebooting device..."
fastboot reboot || log_error "Failed to reboot device."
log_success "PREEMPT_RT Kernel flashed and device rebooting. You can verify with 'adb shell cat /proc/version' or 'adb shell cat /sys/kernel/realtime'."
The adb shell cat /sys/kernel/realtime command should output 1 if PREEMPT_RT is active.
Complete Automation Script
Here’s the full script assembly:
#!/bin/bash
# --- Configuration Variables ---
KERNEL_DIR="$(pwd)/android-kernel"
RT_PATCH_VERSION="6.1.72-rt20" # Match your kernel version
DEVICE_CODENAME="raven" # Example: Pixel 6 Pro
FASTBOOT_IMAGE_NAME="Image.gz" # Common for newer kernels, may be Image.gz-dtb or Image
# Toolchain variables (ensure these match your environment)
export NDK_ROOT="/home/user/android-ndk-r25c"
export PATH="$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH"
export CROSS_COMPILE="$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-"
export ARCH="arm64"
# Kernel configuration
DEFCONFIG="gki_defconfig" # Example, adjust for your kernel
MAKE_JOBS=$(nproc)
# --- Functions for logging ---
log_info() { echo -e "
[INFO] $1
"; }
log_error() { echo -e "
[ERROR] $1
" >&2; exit 1; }
log_success() { echo -e "
[SUCCESS] $1
"; }
# --- Main Script Logic ---
log_info "Starting PREEMPT_RT Android Kernel Automation for $DEVICE_CODENAME..."
# Step 1: Clone Kernel Source
if [ ! -d "$KERNEL_DIR" ]; then
log_info "Cloning kernel source for $DEVICE_CODENAME..."
git clone https://android.googlesource.com/kernel/common.git "$KERNEL_DIR"
cd "$KERNEL_DIR"
git checkout android-6.1-r-gsi # Or your specific branch/tag
cd ..
else
log_info "Kernel directory $KERNEL_DIR already exists. Pulling latest changes."
cd "$KERNEL_DIR"
git reset --hard
git clean -fdx
git pull
cd ..
fi
# Step 2: Download and Apply PREEMPT_RT Patch
log_info "Downloading PREEMPT_RT patch $RT_PATCH_VERSION..."
RT_PATCH_FILE="patch-${RT_PATCH_VERSION}.patch.gz"
wget -nc https://www.kernel.org/pub/linux/kernel/projects/rt/6.1/older/"$RT_PATCH_FILE" || log_error "Failed to download RT patch."
log_info "Applying PREEMPT_RT patch..."
gunzip -c "$RT_PATCH_FILE" | patch -d "$KERNEL_DIR" -p1 || log_error "Failed to apply RT patch. Check kernel version and patch compatibility."
# Step 3: Configure Kernel
log_info "Entering kernel directory $KERNEL_DIR..."
cd "$KERNEL_DIR" || log_error "Could not enter kernel directory."
log_info "Generating default config from $DEFCONFIG..."
make $DEFCONFIG || log_error "Failed to generate default config."
log_info "Enabling PREEMPT_RT features in .config..."
./scripts/config --file .config -e PREEMPT_RT_BASE
./scripts/config --file .config -e PREEMPT_RT_FULL
./scripts/config --file .config -d PREEMPT_VOLUNTARY
# Optional: Customize more specific kernel features here using ./scripts/config
# For full automation, consider replacing make menuconfig with a pre-configured .config
# cp /path/to/my_rt_config .config
log_info "Running make menuconfig for final review (save and exit to continue)..."
make menuconfig || log_error "make menuconfig failed."
log_info "Saving current .config as a new defconfig for future use..."
make savedefconfig
cp defconfig arch/$ARCH/configs/${DEFCONFIG}_rt || log_error "Failed to save RT defconfig."
# Step 4: Build Kernel and Modules
log_info "Building kernel $FASTBOOT_IMAGE_NAME and modules (using $MAKE_JOBS jobs)..."
make -j$MAKE_JOBS || log_error "Kernel build failed."
make modules_install INSTALL_MOD_PATH="$(pwd)/modules_install" || log_error "Modules install failed."
KERNEL_IMAGE_PATH="arch/$ARCH/boot/$FASTBOOT_IMAGE_NAME"
if [ ! -f "$KERNEL_IMAGE_PATH" ]; then
log_error "Kernel image not found at $KERNEL_IMAGE_PATH. Check FASTBOOT_IMAGE_NAME and ARCH."
fi
log_success "Kernel build completed: $KERNEL_IMAGE_PATH"
# Step 5: Flash Kernel to Device
log_info "Attempting to flash kernel to device... Ensure device is in fastboot mode."
log_info "Connecting to device via fastboot..."
fastboot devices || log_error "No fastboot devices found. Is your device in bootloader mode?"
log_info "Flashing $KERNEL_IMAGE_PATH to boot_a partition..."
fastboot flash boot_a "$KERNEL_IMAGE_PATH" || log_error "Fastboot flash failed. Ensure correct partition and image."
log_info "Rebooting device..."
fastboot reboot || log_error "Failed to reboot device."
log_success "PREEMPT_RT Kernel patching, build, and flashing process completed successfully for $DEVICE_CODENAME!"
log_info "Verify PREEMPT_RT status: 'adb shell cat /sys/kernel/realtime' should output '1'."
Conclusion
Automating the PREEMPT_RT patching, building, and flashing process for Android kernels dramatically reduces the overhead associated with real-time system development. This script provides a robust foundation, allowing developers to focus on application logic rather than tedious infrastructure tasks. While device-specific adjustments (kernel source, configuration, and flashing commands) are inevitable, this framework significantly accelerates the development cycle, making the integration of real-time capabilities into Android devices more efficient and accessible.
Android Mobile Specs & Compare Directory
Are you researching mobile hardware properties, processor SoCs, GPU chipsets, or RAM configurations? Access our complete specs catalog to compare up to 5 devices side-by-side!
Compare Devices Specs →