Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ jobs:
run: tools/ci/fetch-openssl-statics.sh # picks up $OPENSSL_ANDROID_ROOT from the image
- name: Gradle assemble + lint
run: ./gradlew --no-daemon assembleDebug assembleRelease lint
- name: Check 16 KB .so alignment
run: |
for apk in app/build/outputs/apk/*/*.apk; do
tools/ci/check-so-alignment.sh "$apk"
done
- uses: actions/upload-artifact@v4
with:
name: apk
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/jni/Application.mk
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
# at API 24+.
APP_ABI := arm64-v8a x86_64
APP_PLATFORM := android-24

# Play requires 16 KB-aligned LOAD segments at targetSdk 35+; r26d's lld still defaults to 4 KB.
APP_LDFLAGS := -Wl,-z,max-page-size=16384
65 changes: 65 additions & 0 deletions tools/ci/check-so-alignment.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/usr/bin/env bash
#
# Fail if any packaged .so has a LOAD segment aligned below 16 KB. Play rejects those
# at targetSdk 35+, and nothing in a normal build says so — the regression is silent.
set -euo pipefail

APK="${1:?usage: $0 <apk>}"
WANT=16384

# The toolchain image carries the NDK but no binutils, so fall back to its llvm-readelf.
READELF="$(command -v llvm-readelf || command -v readelf || true)"
if [ -z "$READELF" ]; then
for cand in "${ANDROID_NDK_ROOT:-${ANDROID_NDK_HOME:-/nonexistent}}"/toolchains/llvm/prebuilt/*/bin/llvm-readelf; do
[ -x "$cand" ] && READELF="$cand" && break
done
fi
[ -n "$READELF" ] || {
echo "check-so-alignment: no readelf/llvm-readelf found" >&2
exit 1
}

tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
mkdir -p "$tmp/lib"
# 11 is "nothing matched", which the count check below reports in its own words.
rc=0
unzip -q -o "$APK" 'lib/*' -d "$tmp" || rc=$?
if [ "$rc" -ne 0 ] && [ "$rc" -ne 11 ]; then
echo "check-so-alignment: cannot extract $APK (unzip rc=$rc)" >&2
exit 1
fi

# Cross-check the walk against the archive listing. find's exit status is invisible to set -e
# from inside a process substitution, so a truncated walk would silently check a subset and
# still report success; comparing counts asserts completeness, not merely non-emptiness.
# unzip -Z1 exits 11 when the pattern matches nothing, which is the likely regression here
# (a build shipping no native libs at all), so name that case rather than blame the archive.
listed="$(unzip -Z1 "$APK" 'lib/*.so' | wc -l)" || {
echo "check-so-alignment: no lib/*.so in $APK, or it is unreadable" >&2
exit 1
}
mapfile -t sos < <(find "$tmp/lib" -type f -name '*.so' | sort)
if [ "${#sos[@]}" -ne "$listed" ]; then
echo "check-so-alignment: $APK lists $listed .so, walked ${#sos[@]}" >&2
exit 1
fi

rc=0
for so in "${sos[@]}"; do
name="${so#"$tmp"/}"
aligns="$("$READELF" -lW "$so" | awk '$1 == "LOAD" { print $NF }')"
[ -n "$aligns" ] || {
echo "check-so-alignment: no LOAD segments in $name" >&2
exit 1
}
for a in $aligns; do
if [ "$((a))" -lt "$WANT" ]; then
echo "FAIL $name: LOAD p_align $a < $WANT"
rc=1
fi
done
done

[ "$rc" -eq 0 ] && echo "16 KB aligned: ${#sos[@]} .so in $(basename "$APK")"
exit "$rc"
Loading