Build KernelSU for Pixel Device

sn00py z0r0sn00py z0r0
8 min read

Note: This article is only available for devices without GKI (Pixel 5 and below, which Google calls Legacy Pixel) or MSM Project

Requirement

  • Pixel Device (recommend last oldest version, in this article is Pixel 3XL, image used image-crosshatch-qq3a.200805.001)

  • Ubuntu machine (With 8-16 cores CPU, RAM higher than 16Gb, Hard Disk available at least 150Gb)

Pull it!

The first thing you need to do is ensure that the kernel you build can run basic functionalities such as touch, Wi-Fi, etc. Based on the kernel to be determined branch name of kernel

The commid id we are looking for is “dee0d123b122”. In my experience, I will go to Kernel MSM and find device_name-versionKernel-androidx (in my case is crosshatch-4.9-android10) then check all of branch to find matched. I found android-msm-crosshatch-4.9-android10-qpr3 have commit id is dee0d123b122058c6eeeee7cec14548e2c037131 matched with my kernel running on my Pixel device

Normally, projects from Google like AOSP will use repo to manage the project instead of git, so firstly, install repo first, we also need to install requirement liked make or g++‘s library

sudo apt-get install sudo apt-get install make python-is-python3 gcc libssl-dev git-core gnupg flex bison build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386  x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig make
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/repo
chmod a+x ~/repo
sudo mv ~/repo /usr/bin/repo

Create kernel folder and clone kernel

# Config git is necessary
git config --global user.name "<your name>"
git config --global user.email "<your name>"
# Create and clone with repo
mkdir kernel && cd kernel
repo init -u https://android.googlesource.com/kernel/manifest -b android-msm-crosshatch-4.9-android10-qpr3
repo sync

It will take your time (~10 mins)

Sync is done and your kernel on the device

Build it

We have many ways to build but in my experience, we should extract ramdisk on original image and build kernel from that to make sure that touch and wifi can work. In this article, I will follow that methods.

Prepare for build

Modify build code

At this time, build tool (it will pull when you use repo to clone kernel source) only support for BOARD_HEADER_VERSION 3 so our devices is BOARD_HEADER_VERSION 2 will out of scope, we also need to rollback

cd build
git checkout ec7e1bc932f45518c6368bf0275b99639b904001

To make sure that we correct build tool, please check conditional logic code in build.sh

cat build.sh | grep "-eq \"3\""

Extract boot.img

When we get firmware from Google, we will see .zip folder, let unpack it and get boot.img file

Use Android Image Kitchen to extract boot.img. We will get something like build parameters, randisk file, etc. Put boot.img inside AIK-Linux folder, then extract boot.img

git clone https://github.com/draekko/AIK-Linux.git && cd AIK-Linux
# Move boot.img inside AIK-Linux
./unpackimg.sh boot.img
Android Image Kitchen - UnpackImg Script
by osm0sis @ xda-developers

Supplied image: boot.img

Setting up work folders...

Image type: AOSP

Signature with "AVBv2" type detected.

Splitting image to "split_img/"...
ANDROID! magic found at: 0
BOARD_KERNEL_CMDLINE console=ttyMSM0,115200n8 androidboot.console=ttyMSM0 printk.devkmsg=on msm_rtb.filter=0x237 ehci-hcd.park=3 service_locator.enable=1 cgroup.memory=nokmem lpm_levels.sleep_disabled=1 usbcore.autosuspend=7 loop.max_part=7 androidboot.boot_devices=soc/1d84000.ufshc androidboot.super_partition=system buildvariant=user
BOARD_KERNEL_BASE 0x00000000
BOARD_NAME
BOARD_PAGE_SIZE 4096
BOARD_HASH_TYPE sha1
BOARD_KERNEL_OFFSET 0x00008000
BOARD_RAMDISK_OFFSET 0x01000000
BOARD_SECOND_OFFSET 0x00f00000
BOARD_TAGS_OFFSET 0x00000100
BOARD_OS_VERSION 10.0.0
BOARD_OS_PATCH_LEVEL 2020-08
BOARD_HEADER_VERSION 2
BOARD_HEADER_SIZE 1660
BOARD_DTB_SIZE 862396
BOARD_DTB_OFFSET 0x01f00000

Unpacking ramdisk (as root) to "ramdisk/"...

Compression used: gzip
40878 blocks

Done!

Please note this log, after unpacking have new ramdisk and split_img folders. We found split_img\boot.img-ramdisk.cpio.gz is ramdisk, unzip it and move to kernel root folder

gzip -dk split_img/boot.img-ramdisk.cpio.gz
mv split_img/boot.img-ramdisk.cpio ../kernel/ # Move to root kernel

Get mkbootimg

Inside root folder of kernel get mkbootimg.py. Here I will manual copy mkbootimg.py

Analyse build code

This part can skip, but please modify build/build.sh first. Please add below before Files copied to… line

if [ -f "${VENDOR_RAMDISK_BINARY}" ]; then
  cp ${VENDOR_RAMDISK_BINARY} ${DIST_DIR}
fi  

echo "========================================================"
echo " Files copied to ${DIST_DIR}"

Now you can skip to next part 😔, or see my analyse build code to know how to build the kernel

My target here is use BUILD_BOOT_IMG to create boot.img. This will help me avoid compatibility during create boot.img. In the note of build code mentioned we need some information

#     - MKBOOTIMG_PATH=<path to the mkbootimg.py script which builds boot.img>
#       (defaults to tools/mkbootimg/mkbootimg.py)
#     - GKI_RAMDISK_PREBUILT_BINARY=<Name of the GKI ramdisk prebuilt which includes
#       the generic ramdisk components like init and the non-device-specific rc files>
#     - VENDOR_RAMDISK_BINARY=<Name of the vendor ramdisk binary which includes the
#       device-specific components of ramdisk like the fstab file and the
#       device-specific rc files.>
#     - KERNEL_BINARY=<name of kernel binary, eg. Image.lz4, Image.gz etc>
#     - BOOT_IMAGE_HEADER_VERSION=<version of the boot image header>
#       (defaults to 3)
#     - KERNEL_CMDLINE=<string of kernel parameters for boot>
#     - KERNEL_VENDOR_CMDLINE=<string of kernel parameters for vendor boot image,
#       vendor_boot when BOOT_IMAGE_HEADER_VERSION >= 3; boot otherwise>
#     - VENDOR_FSTAB=<Path to the vendor fstab to be included in the vendor
#       ramdisk>
#     If the BOOT_IMAGE_HEADER_VERSION is less than 3, two additional variables must
#     be defined:
#     - BASE_ADDRESS=<base address to load the kernel at>
#     - PAGE_SIZE=<flash page size>

So we need

  • MKBOOTIMG_PATH => We already have inside kernel root folder

  • GKI_RAMDISK_PREBUILT_BINARY => We can skip because inside code, it only use if BOOT_IMAGE_HEADER_VERSION is more than 3 => We 2 now

  • VENDOR_RAMDISK_BINARY => Path of boot.img-ramdisk.cpio file extracted from .gz file

  • KERNEL_BINARY => Used default name Image.lz4, lz4 is compress type of pixel image

  • BOOT_IMAGE_HEADER_VERSION => It is 2 (get from AIK)

  • KERNEL_CMDLINE => From AIK

  • KERNEL_VENDOR_CMDLINE => Can skip (BOOT_IMAGE_HEADER_VERSION > 3)

  • VENDOR_FSTAB => Can skip (BOOT_IMAGE_HEADER_VERSION > 3)

  • BASE_ADDRESS => From AIK

  • PAGE_SIZE => From AIK

Build

To build it compare all and use build/build.sh. I will use private/msm-google/build.config.common config to avoid bug

BUILD_CONFIG=private/msm-google/build.config.bluecross BUILD_BOOT_IMG=1 MKBOOTIMG_PATH=mkbootimg.py VENDOR_RAMDISK_BINARY=boot.img-ramdisk.cpio KERNEL_BINARY=Image.lz4 BOOT_IMAGE_HEADER_VERSION=2 KERNEL_CMDLINE="console=ttyMSM0,115200n8 androidboot.console=ttyMSM0 printk.devkmsg=on msm_rtb.filter=0x237 ehci-hcd.park=3 service_locator.enable=1 cgroup.memory=nokmem lpm_levels.sleep_disabled=1 usbcore.autosuspend=7 loop.max_part=7 androidboot.boot_devices=soc/1d84000.ufshc androidboot.super_partition=system buildvariant=user" BASE_ADDRESS=0x00000000 PAGE_SIZE=4096 build/build.sh

Choose BUILD_CONFIG affects whether your device has touch or not. My recommend its use BUILD_CONFIG inside private/msm-google.

Some repo have a confuse name like build.config.bluecross and build.config.bonito, like Pixel 3, bluehatch and crosshatch is Pixel 3 and Pixel 3XL; bonito is Pixel 3a, if we build bonito config and flash to 3XL its can make device not working. One point is check DEFCONFIG inside build.config file. Like my config blue.config.bluecross use DEFCONFIG=b1c1_defconfig b1c1 is name of Pixel 3/3XL (I found this information inside android-info.txt, inside .zip file in firmware)

It will stuck at LTO vmlinux.o, if stuck its maybe work 😂

After build boot.img placed in out/android-msm-pixel-4.9/dist/boot.img

We will try to boot this file via fastboot. This only boot its mean if you reboot, its will disappear. You can revert to your kernel by restart device

adb reboot bootloader
fastboot boot out/android-msm-pixel-4.9/dist/boot.img

After boot, make sure that touch and wifi work, you can check to make sure that you running on custom kernel by below command. Original kernel will have (abfarm) but custom build can be customize username, hostname

adb shell cat /proc/version
# Linux version 4.9.210 (build-user@build-host) (Android (5484270 based on r353983c) clang version 9.0.3 (https://android.googlesource.com/toolchain/clang 745b335211bb9eadfa6aa6301f84715cee4b37c5) (https://android.googlesource.com/toolchain/llvm 60cf23e54e46c807513f7a36d0a7b777920b5881) (based on LLVM 9.0.3svn)) #1 SMP PREEMPT 2020-06-08 23:19:21

If everything work, you can be applied by fastboot flash boot or continue to patch KernelSU

Patch KernelSU Next

Firstly, running the script

cd private/msm-google
curl -LSs "https://raw.githubusercontent.com/KernelSU-Next/KernelSU-Next/next/kernel/setup.sh" | bash -

Patch Manual

On non-GKI device, we will have 2 ways to use KernelSU are KPROBES_HOOK and Manually way. Fun fact, Pixel 3 XL is older than Pixel 4 XL but running on Kernel newers than (Pixel 3 is 4.9 but 4.14 on Pixel 4). I do not know why but KPROBES is unstable and I do not know exactly what happends, so I will disabled KSU hook by KPROBES_HOOK and patch manually (Now I know why, please check on next part) Find private/msm-google/KerneSU-Next\kernel\Kconfig

Change default y to default n to disable it

If you want to know we changed successful to Manual, just rebuild and boot to kernel

Follow on Manually modify the kernel source part on KernelSU to patch Kernel

Depends on you kernel, patch is different, on my kernel like this

open.c

open.c

exec.c

read_write.c

stat.c

Just rebuild and flash again.

Why if config not persistence?

Config not persistence because keyring its have bug, its appear on 4.14 kernel version (Pixel 4XL) and can fix by this patch. I recommended that you need to read and patch manually and rebuild and flash

Why still cannot install module?

A strange thing happened is I cannot enable the modules on my Pixel 3. First idea is because KPROBES hook not working but I’m wrong, its will happend even through I patched manually. Try to get log and I see error

Do not permission mean something block it execute system folder :/ What is this? I think its SELinux. After 1-2 hours to research I found issue on Github of KernelSU. And bingo I think my problem here because I used 4.9 kernel

Try to patch security/selinux/hooks.c and waiting to build :d

It worked!!!!!!!!!!!!!!!!!!! In next time if patch can be used hook dont need patch manual for supported kernel

Flash

If everything is work, we need patch persistent to device by

fastboot flash boot boot-new.img

Then install KernelSU Next, please use latest version in tags to compatible with kernel

0
Subscribe to my newsletter

Read articles from sn00py z0r0 directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

sn00py z0r0
sn00py z0r0