# Building Custom Android Kernels: A Deep Dive into the Abyss

**Author:** kelexine  
**Date:** 2025-12-13  
**Category:** Android  
**Tags:** Android, Kernel, Linux, Low-Level, Custom ROM  
**URL:** https://kelexine.is-a.dev/blog/android-kernel-building

---

# The Beautiful Madness of Kernel Development

If you've ever wondered what separates a "ROM developer" from a "kernel developer," here's the brutal truth: about 48 hours of sleep deprivation and a concerning tolerance for cryptic error messages.

I've been building Android kernels for years now, and every time I think I've mastered it, the kernel finds new ways to humble me. This guide is the culmination of countless bootloops, hours of `dmesg` scrolling, and more coffee than any medical professional would recommend.

## Why Build Your Own Kernel?

Before we dive into the technical chaos, let's address the obvious question: **why bother?**

- **Performance**: Tweak schedulers, governors, and I/O settings
- **Features**: Add things your OEM was too lazy to include
- **Learning**: Nothing teaches you Linux internals faster
- **Flex Rights**: "Yeah, I compiled my own kernel" hits different at meetups

> **Warning**: Building kernels will ruin you. Once you start, you can't go back to stock. You've been warned.

## Prerequisites: Setting Up Your Lair

You'll need a Linux machine (or WSL2 if you're feeling adventurous). Here's the bare minimum:

```bash
# Ubuntu/Debian
sudo apt update && sudo apt install -y \
    git-core gnupg flex bison build-essential \
    zip curl zlib1g-dev libc6-dev-i386 libncurses5 \
    x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev \
    libxml2-utils xsltproc unzip fontconfig bc cpio \
    python3 python-is-python3 rsync libssl-dev

# You'll also want some serious storage
# Kernel source + toolchains = 10-20GB easily
```

## Step 1: Acquiring the Source

Every device has its own kernel source. OEMs are legally required to release it (thanks, GPL), though some take their sweet time.

```bash
# Example: Grabbing a device kernel
git clone https://github.com/YourOEM/android_kernel_devicename.git -b android-16 kernel

# This will take a while. Go touch grass.
cd kernel
```

### Understanding the Source Tree

```
kernel/
├── arch/           # Architecture-specific code
│   ├── arm64/      # Your 64-bit ARM magic lives here
│   └── arm/        # 32-bit legacy stuff
├── drivers/        # All the hardware drivers
├── fs/             # Filesystem implementations
├── include/        # Header files everywhere
├── kernel/         # Core kernel code
├── mm/             # Memory management
├── net/            # Networking stack
└── scripts/        # Build helpers
```

The file you'll modify most often: `arch/arm64/configs/your_device_defconfig`

## Step 2: Toolchain Selection

The toolchain is your compiler. This choice matters more than most people realize.

### Option 1: Clang (Recommended)

Google has been pushing Clang hard, and modern kernels are optimized for it.

```bash
# Grab AOSP Clang
mkdir -p ~/toolchains && cd ~/toolchains
git clone --depth=1 https://github.com/AntMan-Kernel/clang.git clang

# Set up environment variables
export PATH="$HOME/toolchains/clang/bin:$PATH"
export CROSS_COMPILE=aarch64-linux-gnu-
export CROSS_COMPILE_ARM32=arm-linux-gnueabi-
export CC=clang
export CLANG_TRIPLE=aarch64-linux-gnu-
```

### Option 2: GCC (Old Reliable)

Some older kernels hate Clang. GCC is your fallback.

```bash
git clone --depth=1 https://github.com/LineageOS/android_prebuilts_gcc_linux-x86_aarch64_aarch64-linux-android-4.9 gcc64
git clone --depth=1 https://github.com/LineageOS/android_prebuilts_gcc_linux-x86_arm_arm-linux-androideabi-4.9 gcc32

export CROSS_COMPILE=$HOME/toolchains/gcc64/bin/aarch64-linux-android-
export CROSS_COMPILE_ARM32=$HOME/toolchains/gcc32/bin/arm-linux-androideabi-
```

## Step 3: Configuration - The Heart of It All

This is where you define what your kernel actually does.

```bash
# Start with your device's default config
make O=out ARCH=arm64 your_device_defconfig

# Want to customize? Open the menu config
make O=out ARCH=arm64 menuconfig
```

### Key Config Options Worth Exploring

```
General setup --->
    [*] Kernel .config support
    [*] Enable access to .config through /proc/config.gz
    Local version - append to kernel release: -kelexine

Power management --->
    CPU Frequency scaling --->
        [*] 'schedutil' cpufreq policy governor
        [*] 'performance' cpufreq policy governor

Kernel Features --->
    Preemption Model (Voluntary Kernel Preemption) --->
        (X) Preemptible Kernel (Low-Latency Desktop)
```

## Step 4: The Build - Time to Cook

Here's the moment of truth. This command will either give you a kernel image or existential dread.

```bash
# The big one
make -j$(nproc --all) O=out \
    ARCH=arm64 \
    CC=clang \
    CROSS_COMPILE=aarch64-linux-gnu- \
    CROSS_COMPILE_ARM32=arm-linux-gnueabi- \
    CLANG_TRIPLE=aarch64-linux-gnu- \
    Image.gz-dtb 2>&1 | tee build.log

# -j$(nproc --all) uses all your CPU cores
# 2>&1 | tee build.log saves output for error hunting
```

### Build Output

If everything works, you'll find your kernel image at:
```
out/arch/arm64/boot/Image.gz-dtb
```

That file is your masterpiece. Guard it with your life.

## Step 5: Packaging - AnyKernel3 is Your Best Friend

Raw kernel images aren't flashable. You need to wrap them in a recovery-flashable package.

```bash
git clone https://github.com/osm0sis/AnyKernel3.git

# Copy your kernel
cp out/arch/arm64/boot/Image.gz-dtb AnyKernel3/

# Edit anykernel.sh for your device
cd AnyKernel3
nano anykernel.sh
```

```bash
# anykernel.sh essentials
kernel.string=Kelexine Kernel
do.devicecheck=1
do.modules=0
do.cleanup=1
device.name1=your_device_codename
device.name2=alternate_codename

block=/dev/block/bootdevice/by-name/boot
```

```bash
# Package it
zip -r9 Kelexine-Kernel-v1.0.zip * -x .git README.md *placeholder
```

## The Debugging Gauntlet

When things go wrong (and they will), here's your toolkit:

### Bootloop? Check These:

```bash
# View kernel logs from recovery
adb shell cat /proc/last_kmsg

# Or use dmesg in a working state
adb shell dmesg | tail -200
```

### Common Errors and Fixes

| Error | Likely Cause | Fix |
|-------|--------------|-----|
| `Image too large` | dtb not appending correctly | Check DT_Overlay in defconfig |
| `Kernel panic - not syncing` | Driver incompatibility | Check vendor modules |
| `Unable to mount /system` | dm-verity/AVB issues | Disable verification |
| `Touchscreen dead` | Wrong firmware path | Check driver configs |

## Advanced: CI/CD Pipeline

Once you're hooked, automate everything with GitHub Actions:

```yaml
name: Build Kernel

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Environment
        run: |
          sudo apt update
          sudo apt install -y bc bison flex libssl-dev
          
      - name: Clone Toolchain
        run: |
          git clone --depth=1 https://github.com/AntMan-Kernel/clang.git ~/clang
          
      - name: Build
        run: |
          export PATH="$HOME/clang/bin:$PATH"
          make O=out ARCH=arm64 your_device_defconfig
          make -j$(nproc) O=out ARCH=arm64 CC=clang Image.gz-dtb
```

## Conclusion

Building Android kernels is a journey. You'll break things. You'll question your life choices at 3 AM staring at a bootlooping device. But when that first custom kernel boots successfully, with your name in `Settings > About Phone > Kernel Version`—there's nothing quite like it.

Welcome to the rabbit hole. There's no coming back.

> **Pro Tip**: Keep a backup device. Seriously. Your daily driver will thank you.

---

**Resources**:
- [Kernel Newbies](https://kernelnewbies.org/)
- [XDA Developers Forums](https://forum.xda-developers.com/)
- [Linux Kernel Documentation](https://www.kernel.org/doc/)

---

*This content is available at [kelexine.is-a.dev/blog/android-kernel-building](https://kelexine.is-a.dev/blog/android-kernel-building)*
