How to Build a Custom Android Kernel
If you’ve ever wondered “how to build an Android kernel”, this guide is for you. Building your own kernel can be a rewarding experience as it will give you a greater degree of control over your Android device, from the CPU, RAM, GPU to even the battery.
This is a very hands-on process that involves a lot of compiling and console commands, but if you’re familiar with Linux (or good at following directions) it should be no problem.
Please note this guide is for non-Mediatek devices.
Other Appual’s articles of interest include:
- How to Build Custom ROM from Android Open Source Project | Pt. 2
- How to Manually Theme Android System UI
If you’re building a custom kernel, you will just need to clone the kernel from Git with commands provided below. But if you’re compiling a stock kernel, you need to know where to get the original kernel from source (for all sorts of reasons).
Original Kernel Sources for Various Brands:
For downloading the kernel, either use a git clone or download the tarball file and extract it.
Here is the git command:
git clone -b <branch_to_checkout> <url> <desired_folder_name>
–OR–
tar -xvf <filename>
So as an example, this would be the command to grab the latest Nexus 6P Nougat 3.10 kernel from Google:
git clone -b android-msm-angler-3.10-nougat-mr2 https://android.googlesource.com/kernel/msm/ angler
This should clone the kernel / msm repo into an angler folder, and automatically checkout the android-msm-angler-3.10-nougat-mr2.
Now because most Android devices are ARM based, we’ll need to use a compiler that will target ARM devices – this means a host/native compiler won’t work, unless you’re compiling on another ARM device. You have a few options here. You can either compile one yourself if you know how, using something like Crosstool-NG. Alternatively, you can download a prebuilt compiler – such as the one Google provides for Arm 32-bit and Arm64.
Before downloading a prebuilt compiler, you need to know the exact architecture of your device, so use an app like CPU-Z to determine it.
One other popular toolchain would be UberTC – but for any kernels higher than 4.9, you’ll need to patch them, and compiling with Google’s toolchain first is best practice.
In any case, once you’ve decided on the toolchain, you need to clone it.
git clone <url>
Now point the Makefile to your compiler, running it from within the toolchain folder.
- export CROSS_COMPILE=$(pwd)/bin/<toolchain_prefix>-
Example:
- export CROSS_COMPILE=$(pwd)/bin/aarch64-linux-android-
Now tell the Makefile your device architecture.
- export ARCH=<arch> && export SUBARCH=<arch>
Example:
- export ARCH=arm64 && export SUBARCH=arm64
Locate your proper defconfig by navigating to the arch/<arch>/configs folder within the kernel source (e.g. arch/arm64/configs).
Next locate the developer’s proper config file for the kernel you are building. It should typically be in the form of <codename>_defconfig or <kernel_name>_defconfig. The defconfig will instruct the compiler what options to include in the kernel.
Generic Qualcomm configs may also be found, these will usually be something like (msm-perf_defconfig, msmcortex-perf_defconfig).
Building the Kernel
Code:
make clean
make mrproper
make <defconfig_name>
make -j$(nproc –all)
When those commands are successful, you should have: an Image, Image-dtb, Image.gz, or Image.gz-dtb file at the end.
If those commands failed, you might need to specify the output directory when making a new CAF based kernel, like this:
mkdir -p out
make O=out clean
make O=out mrproper
make O=out <defconfig_name>
make O=out -j$(nproc –all)
If it still doesn’t want to work, something is broken – check your headers or bring it up with the kernel developers.
If the kernel was successfully compiled, you now need to flash it. There are two different ways of doing this – you can unpack and repack the bootimage using either Android Image Kitchen or AnyKernel2.
There may also be some nuances based on specific devices – you’ll need to ask your device developers for assistance if this is the case.
Flashing the Kernel in Android Image Kitchen
Download Android Image Kitchen
Extract your Android device’s boot image from the latest available image (whether stock or custom ROM).
Now unpack the image using this code:
unpackimg.sh <image_name>.img
Next locate the zImage file, and replace it with your compiled kernel image – rename it to what was in the boot image.
Now run this code to repack the image:
repackimg.sh
Now you can flash the new boot image using fastboot, TWRP, etc.
Flashing the Kernel in AnyKernel2
Download the latest AnyKernel2
Apply this patch to flush out all the demo files.
wget https://github.com/nathanchance/AnyKernel2/commit/addb6ea860aab14f0ef684f6956d17418f95f29a.diff
patch -p1 < addb6ea860aab14f0ef684f6956d17418f95f29a.diff
rm addb6ea860aab14f0ef684f6956d17418f95f29a.diff
Now place your kernel image in the root of the file, and open the anykernel.sh to modify these values:
- string: your kernel name
- name#: List all of your device’s codenames (from the /system/build.prop: ro.product.device, ro.build.product)
- block: Your boot image’s path in your fstab. The fstab can be opened from the root of your device and it will look something like this: https://android.googlesource.com/dev…r/fstab.angler
The first column is the value you want to set block to.
Now re-zip the kernel, and flash it in AnyKernel2:
zip -r9 kernel.zip * -x README.md kernel.zip
Be warned that many kernels from CAF include a Python script that will trigger –Werror, which basically causes your build to throw errors at the tiniest of things. So for higher GCC versions (which include more warnings), you’ll typically need to make changes in the Makefile:
diff --git a/Makefile b/Makefile
index 1aaa760f255f..bfccd5594630 100644
--- a/Makefile
+++ b/Makefile
@@ -326,7 +326,7 @@ include $(srctree)/scripts/Kbuild.include
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
-REAL_CC = $(CROSS_COMPILE)gcc
+CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
@@ -340,10 +340,6 @@ DEPMOD = /sbin/depmod
PERL = perl
CHECK = sparse
-# Use the wrapper for the compiler. This wrapper scans for new
-# warnings and causes the build to stop upon encountering them.
-CC = $(srctree)/scripts/gcc-wrapper.py $(REAL_CC)
-
CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
-Wbitwise -Wno-return-void $(CF)
CFLAGS_MODULE =
Using a higher GCC toolchain (5.x, 6.x, 7.x or even 8.x) will require you to nuke the GCC wrapper script as above and use a unified GCC header file (pick the following if you have an include/linux/compiler-gcc#.h file):
3.4/3.10: https://git.kernel.org/pub/scm/linux…9bb8868d562a8a
3.18: https://git.kernel.org/pub/scm/linux…9f67d656b1ec2f
Even if you get a lot of warnings, they’re not necessary to fix (typically).
Your kernel is built and ready to go!