Skip to content

fix: import re in ReSukiSU SUSFS compat #1

fix: import re in ReSukiSU SUSFS compat

fix: import re in ReSukiSU SUSFS compat #1

name: Build ABK App Dev
on:
workflow_dispatch:
push:
paths:
- "app/**"
- "app_dev/**"
- "build.gradle.kts"
- "settings.gradle.kts"
- "gradle/**"
- ".github/workflows/build-abk-app-dev.yml"
- ".github/actions/prepare-abk-app-inputs/**"
pull_request:
paths:
- "app/**"
- "app_dev/**"
- "build.gradle.kts"
- "settings.gradle.kts"
- "gradle/**"
- ".github/workflows/build-abk-app-dev.yml"
- ".github/actions/prepare-abk-app-inputs/**"
jobs:
build:
runs-on: ${{ vars.APP_RUNNER || 'ubuntu-latest' }}
permissions:
contents: read
actions: read
env:
HAS_RELEASE_SIGNING: ${{ secrets.ABK_RELEASE_KEYSTORE_BASE64 != '' && secrets.ABK_RELEASE_STORE_PASSWORD != '' && secrets.ABK_RELEASE_KEY_ALIAS != '' && secrets.ABK_RELEASE_KEY_PASSWORD != '' }}
SUKISU_ULTRA_REPO: https://github.com/SukiSU-Ultra/SukiSU-Ultra.git
SUKISU_ULTRA_REF: main
SUKISU_KSUD_ABIS: arm64-v8a,armeabi-v7a,x86_64
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: "17"
- name: Set up Android SDK
uses: android-actions/setup-android@v3
- name: Install Android SDK packages
run: sdkmanager --channel=3 "platforms;android-37.0" "build-tools;37.0.0" "cmake;3.22.1" "ndk;28.2.13676358"
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
with:
gradle-version: "9.3.1"
cache-read-only: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository }}
- name: Set up Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-linux-android,armv7-linux-androideabi,x86_64-linux-android,aarch64-unknown-linux-musl,x86_64-unknown-linux-musl
- name: Prepare ABK app inputs
id: abk-inputs
uses: ./.github/actions/prepare-abk-app-inputs
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Cache Cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: abk-cargo-registry-v1-linux
restore-keys: abk-cargo-registry-v1-
- name: Cache ksud outputs
id: ksud-cache
uses: actions/cache@v4
with:
path: |
app/build/generated/abk-assets/main
app/build/generated/abk-jniLibs/main
key: abk-ksud-v1-${{ steps.abk-inputs.outputs.sukisu_commit }}-${{ steps.abk-inputs.outputs.ksud_abis_key }}-${{ steps.abk-inputs.outputs.workflow_digest }}
- name: Verify ksud cache
id: ksud-verify
run: |
set -euo pipefail
expected="${{ steps.abk-inputs.outputs.sukisu_commit }}"
props="app/build/generated/abk-assets/main/ksud/source.properties"
if [ "${{ steps.ksud-cache.outputs.cache-hit }}" != "true" ] || [ ! -f "$props" ]; then
echo "needs_rebuild=true" >> "$GITHUB_OUTPUT"
echo "ksud cache: miss"
exit 0
fi
actual="$(grep '^commit=' "$props" | cut -d= -f2- | tr -d '\r')"
if [ "$actual" != "$expected" ]; then
echo "ksud cache: stale (expected=$expected actual=$actual)"
rm -rf app/build/generated/abk-assets/main app/build/generated/abk-jniLibs/main
echo "needs_rebuild=true" >> "$GITHUB_OUTPUT"
else
echo "ksud cache: hit (commit=$actual)"
echo "needs_rebuild=false" >> "$GITHUB_OUTPUT"
fi
- name: Build bundled SukiSU-Ultra ksud assets
if: steps.ksud-verify.outputs.needs_rebuild == 'true'
env:
ANDROID_NDK_HOME: ${{ env.ANDROID_HOME }}/ndk/28.2.13676358
run: |
set -euo pipefail
source_dir="$RUNNER_TEMP/sukisu-ultra"
target_dir="$GITHUB_WORKSPACE/app/build/generated/abk-assets/main/ksud"
jni_target_dir="$GITHUB_WORKSPACE/app/build/generated/abk-jniLibs/main"
cargo_target_dir="$source_dir/target"
repo_url="${SUKISU_ULTRA_REPO%.git}"
rm -rf "$source_dir" "$target_dir" "$jni_target_dir"
git clone --depth 1 --branch "$SUKISU_ULTRA_REF" "$SUKISU_ULTRA_REPO" "$source_dir"
commit="$(git -C "$source_dir" rev-parse HEAD)"
mkdir -p "$target_dir" "$jni_target_dir"
setup_rust_build() {
local triple="$1"
local android_sdk_level="$2"
local llvm_path="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64"
local llvm_bin="$llvm_path/bin"
unset RUSTFLAGS
local ndk_triple="$triple"
if [ "$ndk_triple" = "armv7-linux-androideabi" ]; then
ndk_triple="armv7a-linux-androideabi"
fi
local clang_path="$llvm_bin/${ndk_triple}${android_sdk_level}-clang"
local utriple="${triple//-/_}"
local uutriple="${utriple^^}"
export "CC_${utriple}=$clang_path"
export "CXX_${utriple}=${clang_path}++"
export "AR_${utriple}=$llvm_bin/llvm-ar"
export "CARGO_TARGET_${uutriple}_LINKER=$clang_path"
export "BINDGEN_EXTRA_CLANG_ARGS_${utriple}=--sysroot=$llvm_path/sysroot -I$llvm_path/sysroot/usr/include/$triple"
}
setup_ksuinit_build() {
local triple="$1"
local llvm_path="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64"
local llvm_bin="$llvm_path/bin"
local linker=""
local env_key=""
unset RUSTFLAGS
case "$triple" in
aarch64-unknown-linux-musl)
linker="$llvm_bin/aarch64-linux-android26-clang"
env_key="CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER"
export RUSTFLAGS="-C link-arg=-no-pie"
;;
x86_64-unknown-linux-musl)
linker="$llvm_bin/x86_64-linux-android26-clang"
env_key="CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER"
;;
*)
echo "::error::Unsupported ksuinit target: $triple"
return 1
;;
esac
export "$env_key=$linker"
}
triples_for_abi() {
case "$1" in
arm64-v8a) printf '%s\n' "aarch64-linux-android" ;;
armeabi-v7a) printf '%s\n' "armv7-linux-androideabi" ;;
x86_64) printf '%s\n' "x86_64-linux-android" ;;
*)
echo "::error::Unsupported ksud ABI: $1"
return 1
;;
esac
}
asset_dir_for_abi() {
case "$1" in
arm64-v8a) printf '%s\n' "aarch64" ;;
armeabi-v7a) printf '%s\n' "arm" ;;
x86_64) printf '%s\n' "x86_64" ;;
*)
echo "::error::Unsupported asset ABI: $1"
return 1
;;
esac
}
ksuinit_target_for_abi() {
case "$1" in
arm64-v8a) printf '%s\n' "aarch64-unknown-linux-musl" ;;
armeabi-v7a) printf '%s\n' "" ;;
x86_64) printf '%s\n' "x86_64-unknown-linux-musl" ;;
*)
echo "::error::Unsupported ksuinit ABI: $1"
return 1
;;
esac
}
build_ksuinit_binary() {
local triple="$1"
[ -n "$triple" ] || return 0
setup_ksuinit_build "$triple"
cargo build \
--package ksuinit \
--target "$triple" \
--release \
--target-dir "$cargo_target_dir" \
--manifest-path "$source_dir/Cargo.toml"
}
{
echo "source_repo=$repo_url"
echo "ref=$SUKISU_ULTRA_REF"
echo "commit=$commit"
echo "abis=$SUKISU_KSUD_ABIS"
echo "built_by=.github/workflows/build-abk-app-dev.yml"
} > "$target_dir/source.properties"
build_ksuinit_binary "aarch64-unknown-linux-musl"
build_ksuinit_binary "x86_64-unknown-linux-musl"
aarch64_ksuinit="$cargo_target_dir/aarch64-unknown-linux-musl/release/ksuinit"
x86_64_ksuinit="$cargo_target_dir/x86_64-unknown-linux-musl/release/ksuinit"
IFS=',' read -ra abi_list <<< "$SUKISU_KSUD_ABIS"
for abi in "${abi_list[@]}"; do
abi="$(printf '%s' "$abi" | xargs)"
[ -n "$abi" ] || continue
triple="$(triples_for_abi "$abi")"
asset_dir="$(asset_dir_for_abi "$abi")"
bin_dir="$source_dir/userspace/ksud/bin/$asset_dir"
mkdir -p "$bin_dir"
ksuinit_target="$(ksuinit_target_for_abi "$abi")"
if [ -n "$ksuinit_target" ]; then
ksuinit_binary="$cargo_target_dir/$ksuinit_target/release/ksuinit"
else
ksuinit_binary="$aarch64_ksuinit"
echo "warning.$abi=ksuinit_fallback_aarch64" >> "$target_dir/source.properties"
fi
if [ ! -f "$ksuinit_binary" ]; then
echo "::error::ksuinit binary missing for $abi"
find "$cargo_target_dir" -maxdepth 4 -type f -name 'ksuinit' | sort || true
exit 1
fi
install -Dm755 "$ksuinit_binary" "$bin_dir/ksuinit"
setup_rust_build "$triple" 26
cargo build \
--target "$triple" \
--release \
--target-dir "$cargo_target_dir" \
--manifest-path "$source_dir/userspace/ksud/Cargo.toml"
binary=""
for candidate in \
"$cargo_target_dir/$triple/release/ksud" \
"$source_dir/userspace/ksud/target/$triple/release/ksud" \
"$GITHUB_WORKSPACE/target/$triple/release/ksud"
do
if [ -f "$candidate" ]; then
binary="$candidate"
break
fi
done
if [ ! -f "$binary" ]; then
echo "::error::ksud binary missing for $abi ($triple)"
echo "cargo_target_dir=$cargo_target_dir"
find "$source_dir" -maxdepth 4 -type f \( -name 'ksud' -o -name 'ksud.exe' \) | sort || true
find "$GITHUB_WORKSPACE" -maxdepth 4 -type f \( -name 'ksud' -o -name 'ksud.exe' \) | sort || true
exit 1
fi
install -Dm755 "$binary" "$jni_target_dir/$abi/libksud.so"
sha256="$(sha256sum "$binary" | awk '{print tolower($1)}')"
size="$(wc -c < "$binary" | tr -d '[:space:]')"
{
echo "sha256.$abi=$sha256"
echo "size.$abi=$size"
} >> "$target_dir/source.properties"
done
{
echo "### Bundled SukiSU-Ultra ksud"
echo
echo "- Source: $repo_url"
echo "- Ref: $SUKISU_ULTRA_REF"
echo "- Commit: $commit"
echo "- ABIs: $SUKISU_KSUD_ABIS"
echo "- Embedded ksuinit: aarch64-unknown-linux-musl, x86_64-unknown-linux-musl"
echo "- magiskboot: removed upstream (ksud uses bootimg crate)"
} >> "$GITHUB_STEP_SUMMARY"
- name: Cache LKM assets
id: lkm-cache
uses: actions/cache@v4
with:
path: app/src/main/assets/abk_lkm
key: abk-lkm-v1-${{ steps.abk-inputs.outputs.lkm_head_sha }}
- name: Verify LKM cache
id: lkm-verify
run: |
set -euo pipefail
expected="${{ steps.abk-inputs.outputs.lkm_head_sha }}"
props="app/src/main/assets/abk_lkm/source.properties"
if [ "${{ steps.lkm-cache.outputs.cache-hit }}" != "true" ] || [ ! -f "$props" ]; then
echo "needs_rebundle=true" >> "$GITHUB_OUTPUT"
echo "lkm cache: miss"
exit 0
fi
actual="$(grep '^head_sha=' "$props" | cut -d= -f2- | tr -d '\r')"
if [ "$actual" != "$expected" ]; then
echo "lkm cache: stale (expected=$expected actual=$actual)"
rm -rf app/src/main/assets/abk_lkm
mkdir -p app/src/main/assets/abk_lkm
echo "needs_rebundle=true" >> "$GITHUB_OUTPUT"
else
echo "lkm cache: hit (head_sha=$actual)"
echo "needs_rebundle=false" >> "$GITHUB_OUTPUT"
fi
- name: Bundle ABK LKM artifacts
if: steps.lkm-verify.outputs.needs_rebundle == 'true'
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
repo="xingguangcuican6666/ABK_control_module"
workflow="lkm.yml"
target_dir="app/src/main/assets/abk_lkm"
mkdir -p "$target_dir"
rm -rf "$target_dir"/*
api_get() {
local url="$1"
local tmp
tmp="$(mktemp)"
if [ -n "${GITHUB_TOKEN:-}" ] && curl -fsSL \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
"$url" -o "$tmp"; then
cat "$tmp"
rm -f "$tmp"
return 0
fi
rm -f "$tmp"
curl -fsSL -H "Accept: application/vnd.github+json" "$url"
}
download_artifact() {
local url="$1"
local out="$2"
if [ -n "${GITHUB_TOKEN:-}" ] && curl -fsSL -L \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
"$url" -o "$out"; then
return 0
fi
curl -fsSL -L "$url" -o "$out"
}
runs_json="$(api_get "https://api.github.com/repos/$repo/actions/workflows/$workflow/runs?status=success&per_page=1")"
run_id="$(printf '%s' "$runs_json" | jq -r '.workflow_runs[0].id // empty')"
run_sha="$(printf '%s' "$runs_json" | jq -r '.workflow_runs[0].head_sha // empty')"
if [ -z "$run_id" ]; then
echo "::error::未找到 $repo 的成功 LKM action"
exit 1
fi
artifacts_json="$(api_get "https://api.github.com/repos/$repo/actions/runs/$run_id/artifacts?per_page=100")"
artifact_count=0
printf '%s' "$artifacts_json" | jq -r '.artifacts[] | select(.name | endswith("-lkm")) | [.name, .archive_download_url] | @tsv' |
while IFS=$'\t' read -r name url; do
[ -n "$name" ] || continue
variant="${name%%-*}"
remainder="${name#*-}"
kmi="${remainder%-lkm}"
out_dir="$target_dir/$variant"
tmp_dir="$(mktemp -d)"
mkdir -p "$out_dir"
download_artifact "$url" "$tmp_dir/artifact.zip"
unzip -q "$tmp_dir/artifact.zip" -d "$tmp_dir/unpack"
ko_file="$(find "$tmp_dir/unpack" -type f -name '*.ko' | head -n 1)"
if [ -z "$ko_file" ]; then
echo "::error::artifact $name 中没有 .ko 文件"
exit 1
fi
cp "$ko_file" "$out_dir/${kmi}_kernelsu.ko"
artifact_count=$((artifact_count + 1))
rm -rf "$tmp_dir"
done
count="$(find "$target_dir" -type f -name '*.ko' | wc -l | tr -d '[:space:]')"
if [ "$count" -eq 0 ]; then
echo "::error::没有成功打包任何 LKM .ko"
exit 1
fi
{
echo "source=$repo"
echo "workflow=$workflow"
echo "run_id=$run_id"
echo "head_sha=$run_sha"
echo "count=$count"
} > "$target_dir/source.properties"
{
echo "### ABK LKM artifacts"
echo
echo "- Source: $repo"
echo "- Workflow: $workflow"
echo "- Run: $run_id"
echo "- Commit: $run_sha"
echo "- Files: $count"
} >> "$GITHUB_STEP_SUMMARY"
- name: Patch for Dev APK
run: |
cp -rvf "app_dev/build.gradle.kts" "app/build.gradle.kts"
cp -rvf "app_dev/strings.xml" "app/src/main/res/values/strings.xml"
- name: Build debug APK
run: gradle assembleDebug
- name: Decode release keystore
if: ${{ env.HAS_RELEASE_SIGNING == 'true' }}
env:
ABK_RELEASE_KEYSTORE_BASE64: ${{ secrets.ABK_RELEASE_KEYSTORE_BASE64 }}
run: |
mkdir -p app/signing
printf '%s' "$ABK_RELEASE_KEYSTORE_BASE64" | base64 --decode > app/signing/abk-release.jks
- name: Export ABK manager certificate metadata
if: ${{ env.HAS_RELEASE_SIGNING == 'true' }}
env:
ABK_RELEASE_STORE_PASSWORD: ${{ secrets.ABK_RELEASE_STORE_PASSWORD }}
ABK_RELEASE_KEY_ALIAS: ${{ secrets.ABK_RELEASE_KEY_ALIAS }}
ABK_RELEASE_STORE_TYPE: ${{ secrets.ABK_RELEASE_STORE_TYPE }}
run: |
set -euo pipefail
cert="$RUNNER_TEMP/abk-manager-cert.der"
keytool -exportcert \
-keystore app/signing/abk-release.jks \
-storetype "${ABK_RELEASE_STORE_TYPE:-JKS}" \
-storepass "$ABK_RELEASE_STORE_PASSWORD" \
-alias "$ABK_RELEASE_KEY_ALIAS" \
-file "$cert"
size="$(wc -c < "$cert" | tr -d '[:space:]')"
hash="$(sha256sum "$cert" | awk '{print tolower($1)}')"
{
echo "# Official ABK release signing certificate metadata."
echo "# This is public certificate metadata, not a private signing key."
echo "ABK_MANAGER_PACKAGE=com.abk.kernel"
echo "ABK_MANAGER_CERT_SIZE=$size"
echo "ABK_MANAGER_CERT_SHA256=$hash"
} > app/signing/abk-manager-cert.generated.env
{
echo "### ABK manager certificate metadata"
echo
echo '```env'
cat app/signing/abk-manager-cert.generated.env
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
- name: Verify checked-in ABK manager certificate metadata
if: ${{ env.HAS_RELEASE_SIGNING == 'true' }}
run: |
set -euo pipefail
expected="app/signing/abk-manager-cert.env"
actual="app/signing/abk-manager-cert.generated.env"
if [ ! -f "$expected" ]; then
echo "::error::$expected is missing. Commit the public manager certificate metadata so kernel builds can trust the release APK."
exit 1
fi
read_value() {
local file="$1"
local key="$2"
awk -F= -v target="$key" '
/^[[:space:]]*#/ { next }
$1 == target {
value = substr($0, index($0, "=") + 1)
gsub(/^[[:space:]\042\047]+|[[:space:]\042\047]+$/, "", value)
print value
exit
}
' "$file"
}
mismatch=0
for key in ABK_MANAGER_PACKAGE ABK_MANAGER_CERT_SIZE ABK_MANAGER_CERT_SHA256; do
expected_value="$(read_value "$expected" "$key")"
actual_value="$(read_value "$actual" "$key")"
if [ "$expected_value" != "$actual_value" ]; then
echo "::error::$key mismatch: checked-in='$expected_value' generated='$actual_value'"
mismatch=1
fi
done
if [ "$mismatch" -ne 0 ]; then
echo "::error::Update $expected with the generated metadata before building trusted manager kernels."
exit 1
fi
- name: Build release APK
env:
ABK_RELEASE_STORE_FILE: ${{ github.workspace }}/app/signing/abk-release.jks
ABK_RELEASE_STORE_PASSWORD: ${{ secrets.ABK_RELEASE_STORE_PASSWORD }}
ABK_RELEASE_KEY_ALIAS: ${{ secrets.ABK_RELEASE_KEY_ALIAS }}
ABK_RELEASE_KEY_PASSWORD: ${{ secrets.ABK_RELEASE_KEY_PASSWORD }}
run: gradle assembleRelease
- name: Verify signed release APK
if: ${{ env.HAS_RELEASE_SIGNING == 'true' }}
run: |
signed_apk="$(find app/build/outputs/apk/release -type f -name '*-release.apk' ! -name '*unsigned*' | head -n 1)"
if [ -z "$signed_apk" ]; then
echo "No signed release APK found."
find app/build/outputs/apk/release -maxdepth 1 -type f -print
exit 1
fi
"$ANDROID_HOME/build-tools/37.0.0/apksigner" verify --verbose "$signed_apk"
- name: Upload APKs
uses: actions/upload-artifact@v6
with:
name: abk-apks
path: |
app/build/outputs/apk/debug/*.apk
app/build/outputs/apk/release/*.apk
app/signing/abk-manager-cert.generated.env