name: Build Android GKI Kernel on: workflow_dispatch: inputs: enable_susfs: description: "Enable susfs support" required: false default: "true" type: boolean config_source: description: "Choose config source for myconfig" required: true default: "repo" type: choice options: - repo root_solution: description: "Choose root solution to integrate" required: false default: "sukisu" type: choice options: - sukisu - kernelsu - kernelsu-next - none kernel_name: description: "Custom kernel name (optional)" required: false default: "GKI" type: string jobs: build-kernel: runs-on: ubuntu-latest env: ARCH: arm64 SUBARCH: arm64 WORKDIR: ${{ github.workspace }}/kernel steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y \ bc bison build-essential cpio curl flex \ git libncurses-dev libssl-dev \ libelf-dev lzop python3 unzip xz-utils \ zstd rsync ca-certificates wget \ pahole dwarves zip gcc g++ gcc --version - name: Setup toolchains & directories run: | set -e echo "WORKDIR=$WORKDIR" mkdir -p "$WORKDIR" cd "$WORKDIR" # 创建目录结构 mkdir -p clang-r547379 mkdir -p anykernel3 mkdir -p output # 下载 Clang 工具链 echo "=== Downloading Clang toolchain ===" curl -LO https://android.googlesource.com/platform/prebuilts/clang/host/linux-x86/+archive/refs/heads/master/clang-r547379.tar.gz tar -xzf clang-r547379.tar.gz -C clang-r547379 rm clang-r547379.tar.gz # 克隆 GCC 工具链 echo "=== Cloning GCC toolchains ===" git clone https://github.com/LineageOS/android_prebuilts_gcc_linux-x86_aarch64_aarch64-linux-android-4.9 aarch64-linux-android-4.9 --depth=1 git clone https://github.com/LineageOS/android_prebuilts_gcc_linux-x86_arm_arm-linux-androideabi-4.9 arm-linux-androideabi-4.9 --depth=1 echo "✅ Setup toolchains -> OK" - name: Setup & Clone Kernel run: | set -e mkdir -p "$WORKDIR" cd "$WORKDIR" # 克隆内核源码 echo "👉 Cloning kernel source" rm -rf android_kernel_oneplus_sm8650 git clone --depth=1 https://github.com/OPACE3PRO/android_kernel_oneplus_sm8650.git android_kernel_oneplus_sm8650 # 克隆模块源码 echo "👉 Cloning sm8650-modules" rm -rf sm8650-modules git clone --depth=1 https://github.com/OPACE3PRO/android_kernel_oneplus_sm8650-modules.git sm8650-modules echo "✅ Kernel source cloned -> android_kernel_oneplus_sm8650" echo "✅ Modules cloned -> sm8650-modules" echo "=== Directory setup complete ===" ls -la "$WORKDIR" # 设置 KERNEL_DIR 环境变量 echo "KERNEL_DIR=android_kernel_oneplus_sm8650" >> $GITHUB_ENV - name: Show final WORKDIR layout run: | set -e cd "$WORKDIR" echo "Final layout under $WORKDIR:" ls -la - name: Copy and configure kernel config run: | set -euo pipefail echo "WORKDIR=$WORKDIR" if [ -z "${KERNEL_DIR:-}" ]; then echo "KERNEL_DIR is not set. Ensure previous step set it." exit 1 fi SRC="$GITHUB_WORKSPACE/config/config_corvette" KERNEL_PATH="$WORKDIR/$KERNEL_DIR" TARGET_DIR="$KERNEL_PATH/arch/arm64/configs" TARGET="$TARGET_DIR/config_defconfig" echo "Copying $SRC -> $TARGET" if [ ! -f "$SRC" ]; then echo "❌ Source config not found: $SRC" exit 1 fi mkdir -p "$TARGET_DIR" cp -f "$SRC" "$TARGET" # 校验目标存在且非空 if [ -s "$TARGET" ]; then echo "✅ OK: $TARGET exists and is non-empty" ls -la "$TARGET" else echo "❌ Error: $TARGET missing or empty" exit 1 fi - name: Install root solution run: | cd "$WORKDIR/$KERNEL_DIR" export KCONFIG_CONFIG="$PWD/arch/arm64/configs/config_defconfig" echo "👉 选择的 Root 方案:${{ github.event.inputs.root_solution }}" case "${{ github.event.inputs.root_solution }}" in kernelsu) echo "✅ 集成 KernelSU" curl -LSs https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh | bash - echo "ROOT_SUFFIX=_KernelSU" >> $GITHUB_ENV ;; kernelsu-next) echo "✅ 集成 KernelSU-Next" curl -LSs https://raw.githubusercontent.com/KernelSU-Next/KernelSU-Next/next/kernel/setup.sh | bash - echo "ROOT_SUFFIX=_KernelSU-Next" >> $GITHUB_ENV ;; sukisu) echo "✅ 集成 SukiSU-Ultra" curl -LSs https://raw.githubusercontent.com/SukiSU-Ultra/SukiSU-Ultra/main/kernel/setup.sh | bash -s main echo "ROOT_SUFFIX=_SukiSU" >> $GITHUB_ENV ;; none) echo "ℹ️ 未选择任何 Root 方案,跳过" ;; *) echo "❌ 未知的 root_solution: ${{ github.event.inputs.root_solution }}" >&2 exit 1 ;; esac # - name: Susfs patch # run: | # cd $GITHUB_WORKSPACE/kernel/source/$KERNEL_DIR # if [ "${{ inputs.enable_susfs }}" = "true" ]; then # # 获取内核版本,例如 "6.1.130" # KERNEL_VER=$(make kernelversion) # echo "🔍 Detected kernel version: $KERNEL_VER" # # 提取主版本和次版本,生成分支名 # KERNEL_MAJOR=$(echo "$KERNEL_VER" | cut -d. -f1) # KERNEL_MINOR=$(echo "$KERNEL_VER" | cut -d. -f2) # # 自动推测 Android 版本(你可以改为硬编码映射表以更严谨) # if [ "$KERNEL_MAJOR" = "6" ] && [ "$KERNEL_MINOR" = "1" ]; then # SUSFS_BRANCH="gki-android14-6.1" # SUSFS_PATCH="50_add_susfs_in_gki-android14-6.1.patch" # elif [ "$KERNEL_MAJOR" = "5" ] && [ "$KERNEL_MINOR" = "15" ]; then # SUSFS_BRANCH="gki-android14-5.15" # SUSFS_PATCH="50_add_susfs_in_gki-android14-5.15.patch" # elif [ "$KERNEL_MAJOR" = "5" ] && [ "$KERNEL_MINOR" = "10" ]; then # SUSFS_BRANCH="gki-android13-5.10" # SUSFS_PATCH="50_add_susfs_in_gki-android13-5.10.patch" # else # echo "❌ Unsupported kernel version: $KERNEL_VER" # exit 1 # fi # echo "🌿 Cloning susfs4ksu branch: $SUSFS_BRANCH" # git clone https://gitlab.com/simonpunk/susfs4ksu.git # cd susfs4ksu # git switch $SUSFS_BRANCH || { echo "❌ Failed to switch to branch $SUSFS_BRANCH"; exit 1; } # cd .. # echo "📁 Copying susfs source and headers" # cp susfs4ksu/kernel_patches/fs/* fs/ # cp susfs4ksu/kernel_patches/include/linux/* include/linux/ # echo "📦 Applying patch: $SUSFS_PATCH" # cp susfs4ksu/kernel_patches/$SUSFS_PATCH . # patch -p1 < $SUSFS_PATCH || { echo "❌ Failed to apply patch: $SUSFS_PATCH"; exit 1; } # echo "✅ Susfs patch applied successfully" # else # echo "ℹ️ 未启用 Susfs,跳过补丁步骤" # fi - name: Build kernel run: | set -euo pipefail cd "$WORKDIR/$KERNEL_DIR" echo "=== Build start ===" starttime=$(date +'%Y-%m-%d %H:%M:%S') echo "Build started at: $starttime" # 基本变量 export ARCH=arm64 export SUBARCH=arm64 export OUT=out export KERNEL_DEFCONFIG=config_defconfig # 默认 LTO 为 thin export LTO="${LTO:-thin}" echo "LTO mode: $LTO" # 工具链路径 export CLANG_PATH="$WORKDIR/clang-r547379" export GCC64_PATH="$WORKDIR/aarch64-linux-android-4.9" export GCC32_PATH="$WORKDIR/arm-linux-androideabi-4.9" # 将工具链加入 PATH export PATH="${CLANG_PATH}/bin:${GCC64_PATH}/bin:${GCC32_PATH}/bin:${PATH}" # CLANG stack frame limit export CLANG_MAX_STACK_SIZE=8192 export KCFLAGS="-Wno-error=frame-larger-than" echo "Using CLANG_PATH=$CLANG_PATH" which clang || true clang --version || true # 清理输出目录 rm -rf "$OUT" && mkdir -p "$OUT" # 1) 生成 defconfig echo "=== make O=${OUT} ${KERNEL_DEFCONFIG} ===" make O=${OUT} ARCH=${ARCH} ${KERNEL_DEFCONFIG} if [ $? -ne 0 ]; then echo "❌ make ${KERNEL_DEFCONFIG} failed" exit 1 fi # 2) 处理 LTO (none/thin/full) if [ "${LTO}" = "none" ] || [ "${LTO}" = "thin" ] || [ "${LTO}" = "full" ]; then echo "Applying LTO=${LTO} to ${OUT}/.config" if [ "${LTO}" = "none" ]; then scripts/config --file ${OUT}/.config -d LTO_CLANG -e LTO_NONE -d LTO_CLANG_THIN -d LTO_CLANG_FULL -d THINLTO elif [ "${LTO}" = "thin" ]; then scripts/config --file ${OUT}/.config -e LTO_CLANG -d LTO_NONE -e LTO_CLANG_THIN -d LTO_CLANG_FULL -e THINLTO else scripts/config --file ${OUT}/.config -e LTO_CLANG -d LTO_NONE -d LTO_CLANG_THIN -e LTO_CLANG_FULL -d THINLTO fi grep -E "LTO_CLANG|LTO_NONE|LTO_CLANG_THIN|LTO_CLANG_FULL|THINLTO" ${OUT}/.config || true else echo "Invalid LTO value: ${LTO}. Use none|thin|full." exit 1 fi # 3) 构建参数 TH_COUNT=$(nproc) echo "Using ${TH_COUNT} parallel jobs" DEF_ARGS="O=${OUT} \ ARCH=${ARCH} \ CROSS_COMPILE=aarch64-linux-gnu- \ CROSS_COMPILE_COMPAT=arm-linux-gnueabi- \ CC=${CLANG_PATH}/bin/clang \ AR=${CLANG_PATH}/bin/llvm-ar \ NM=${CLANG_PATH}/bin/llvm-nm \ LD=${CLANG_PATH}/bin/ld.lld \ HOSTCC=${CLANG_PATH}/bin/clang \ HOSTCXX=${CLANG_PATH}/bin/clang++ \ OBJCOPY=${CLANG_PATH}/bin/llvm-objcopy \ OBJDUMP=${CLANG_PATH}/bin/llvm-objdump \ READELF=${CLANG_PATH}/bin/llvm-readelf \ OBJSIZE=${CLANG_PATH}/bin/llvm-size \ STRIP=${CLANG_PATH}/bin/llvm-strip \ LLVM_IAS=1 \ LLVM=1 \ KCFLAGS=\"${KCFLAGS}\"" BUILD_ARGS="-j${TH_COUNT} ${DEF_ARGS}" echo "=== Start make (logging to ${OUT}/error.log) ===" chmod -R 777 * rm android/abi_gki_protected_exports_* || true make ${BUILD_ARGS} 2>&1 | tee ${OUT}/error.log || true echo "=== Tail of build log ===" tail -n 200 ${OUT}/error.log || true endtime=$(date +'%Y-%m-%d %H:%M:%S') echo "Build started at: $starttime" echo "Build finished at: $endtime" echo "=== Build step finished (check out/error.log for full log) ===" - name: Check build results run: | set -euo pipefail cd "$WORKDIR/$KERNEL_DIR" echo "=== Build Results ===" if [ -f "out/arch/arm64/boot/Image" ]; then echo "✅ Kernel build successful!" ls -la out/arch/arm64/boot/ ls -la out/vmlinux || true du -h out/arch/arm64/boot/Image || true else echo "❌ Kernel build failed!" echo "=== Last 200 lines of error log ===" if [ -f out/error.log ]; then tail -n 200 out/error.log echo "=== Error summary (last 20 matching lines) ===" grep -iE "error|failed|stop" out/error.log | tail -20 || true else echo "No out/error.log found" fi exit 1 fi - name: Replace Image in anykernel3 run: | set -e WORKDIR=ak3_work ZIP_ORIG=anykernel3.zip NEW_ZIP=anykernel3-${{ github.run_number }}.zip NEW_IMAGE=kernel/${{ env.KERNEL_DIR }}/out/arch/arm64/boot/Image # 创建临时工作目录 rm -rf $WORKDIR mkdir -p $WORKDIR cd $WORKDIR # 解压原刷机包,保持目录结构和权限 unzip ../$ZIP_ORIG # 替换 Image 并设置权限 755 cp ../$NEW_IMAGE ./Image chmod 755 Image # 重新打包刷机包 zip -r ../$NEW_ZIP . -x ".*" cd .. # 验证新 ZIP 结构 echo "=== 新刷机包信息 ===" zipinfo $NEW_ZIP - name: Upload build artifacts uses: actions/upload-artifact@v4 if: always() with: name: kernel-build-${{ github.run_number }} path: | # 内核 Image ${{ github.workspace }}/kernel/${{ env.KERNEL_DIR }}/out/arch/arm64/boot/Image* # Device Tree Blob ${{ github.workspace }}/kernel/${{ env.KERNEL_DIR }}/out/arch/arm64/boot/dts/*/*.dtb # 编译日志 ${{ github.workspace }}/kernel/${{ env.KERNEL_DIR }}/out/error.log # 最终配置文件 ${{ github.workspace }}/kernel/${{ env.KERNEL_DIR }}/out/.config # 替换后的 anykernel3.zip ${{ github.workspace }}/anykernel3-${{ github.run_number }}.zip # Kernel 信息文件 ${{ github.workspace }}/kernel/output/kernel_info.txt