This is a quick guide to cross-compile kernel modules for Android, with particular reference to the J3 2016 LineageOS kernel. The steps outlined work for other devices/kernels as well.
- Having a working NDK toolchain (See here for instructions)
- Kernel sources (J3 2016 Lineage OS: https://github.com/djeman/android_kernel_samsung_j3xnlte/tree/cm-14.1)
- Kernel module source code (We will be using sch_netem.c)
This guide assumes you are on Ubuntu 16.04 LTS, other Linux distributions may be used as long as the Android toolchain is properly installed and a working version of make is available.
Go to the kernel folder and edit the Makefile:
CROSS_COMPILE ?= /…../android-ndk-r16b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-
Note: You need to make sure the toolchain is working or the cross-compilation process will fail.
You now need to set a proper config file before the kernel compilation process can commerce.
This step will create the .config file in the kernel directory; kernel configs for specific devices may be found under arch/arm/configs:
Editing the configuration file:
You now need to edit the configuration file to enable the modules you need that were not included in the original kernel build, to do so edit/add one line for each of them. I am trying to get netem working, so:
We can now compile the whole kernel:
Important: You may ask why we need to compile everything if we are only looking at getting a specific module to work, the reason is that even running modules_prepare won’t create the Modules.symvers file; a missing Modules.symvers results in the following error (logged to dmesg) when trying to load the newly compiled module: sch_netem: no symbol version for module_layout; the error shown on the screen, however, is far more generic: insmod: failed to load /data/local/tmp/sch_netem.ko: Exec format error. (running modprobe -f mod_name.ko forces loading the module and disables this check)
Checking the module format
We now check the file format of our new module .ko and compare it against the ones already present in /lib/modules:
It’s important that vermagic matches that of the existing modules or insmod will fail. (running modprobe -f mod_name.ko forces loading the module and disables this check)
You may also conduct further checks using readelf -h sch_netem.ko
Same vermagic, but mine ends with -dirty
If this happens to you, that means you edited the files in the kernel git repo after cloning it, just go to scripts/setlocalversion and disable the two checks. (Comment out the if blocks)
Uploading the new module on the device
adb push sch_netem.ko /data/local/tmp
No output means everything went well and the module is now loaded. To make sure run lsmod and check if the name appears in the list.