Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Target Android 15: Add ELF alignment verification CI check #5634

Open
wants to merge 3 commits into
base: feature/mike/android-15
Choose a base branch
from
Open
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
39 changes: 35 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,24 +149,55 @@ jobs:
- name: Build
run: ./gradlew androidTestsBuild

- name: Find test APK path
id: find-apk
run: |
TEST_APK_PATH=$(find . -path '*/build/outputs/apk/play/debug/*.apk' -type f -print -quit)
echo "Found test APK at: $TEST_APK_PATH"
echo "apk_path=$TEST_APK_PATH" >> "$GITHUB_OUTPUT"

- name: Make script executable
run: chmod +x scripts/check_elf_alignment.sh

- name: Check native libraries alignment
id: check-alignment
continue-on-error: true
run: ./scripts/check_elf_alignment.sh ${{ steps.find-apk.outputs.apk_path }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about capturing the output and post a summary in the workflow? if you open a failed action now it shows as if Android CI tests fails, and opening the details shows that there are no tests.

Screenshot 2025-02-13 at 10 54 06


- name: Handle native alignment failure
if: steps.check-alignment.outcome == 'failure'
run: |
echo "::error::Native library alignment check failed!"
echo "::error::Please check the native libraries in your APK for correct page size alignment."
exit 1

- name: Run Android Tests
if: steps.check-alignment.outcome == 'success'
run: ./gradlew runFlankAndroidTests

- name: Bundle the Android CI tests report
if: always()
if: |
always() &&
steps.check-alignment.outcome == 'success'
run: find . -type d -name 'fladleResults' | zip -@ -r android-tests-report.zip

- name: Generate json file with failures
if: ${{ failure() }}
if: |
failure() &&
steps.check-alignment.outcome == 'success'
run: cat build/fladle/fladleResults/HtmlErrorReport.html | cut -d\` -f2 >> results.json

- name: Print failure report
if: ${{ failure() }}
if: |
failure() &&
steps.check-alignment.outcome == 'success'
run: |
jq -r '.[] | .label as $id | .items[] | "Test:", $id, "Failure:", .label, "URL:", .url, "\n"' results.json

- name: Upload the Android CI tests report
if: always()
if: |
always() &&
steps.check-alignment.outcome == 'success'
uses: actions/upload-artifact@v4
with:
name: android-tests-report
Expand Down
97 changes: 97 additions & 0 deletions scripts/check_elf_alignment.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/bin/bash
progname="${0##*/}"
progname="${progname%.sh}"
# usage: check_elf_alignment.sh [path to *.so files|path to *.apk]
cleanup_trap() {
if [ -n "${tmp}" -a -d "${tmp}" ]; then
rm -rf ${tmp}
fi
exit $1
}
usage() {
echo "Host side script to check the ELF alignment of shared libraries."
echo "Shared libraries are reported ALIGNED when their ELF regions are"
echo "16 KB or 64 KB aligned. Otherwise they are reported as UNALIGNED."
echo
echo "Usage: ${progname} [input-path|input-APK|input-APEX]"
}
if [ ${#} -ne 1 ]; then
usage
exit
fi
case ${1} in
--help | -h | -\?)
usage
exit
;;
*)
dir="${1}"
;;
esac
if ! [ -f "${dir}" -o -d "${dir}" ]; then
echo "Invalid file: ${dir}" >&2
exit 1
fi
if [[ "${dir}" == *.apk ]]; then
trap 'cleanup_trap' EXIT
echo
echo "Recursively analyzing $dir"
echo
if { zipalign --help 2>&1 | grep -q "\-P <pagesize_kb>"; }; then
echo "=== APK zip-alignment ==="
zipalign -v -c -P 16 4 "${dir}" | egrep 'lib/arm64-v8a|lib/x86_64|Verification'
echo "========================="
else
echo "NOTICE: Zip alignment check requires build-tools version 35.0.0-rc3 or higher."
echo " You can install the latest build-tools by running the below command"
echo " and updating your \$PATH:"
echo
echo " sdkmanager \"build-tools;35.0.0-rc3\""
fi
dir_filename=$(basename "${dir}")
tmp=$(mktemp -d -t "${dir_filename%.apk}_out_XXXXX")
unzip "${dir}" lib/* -d "${tmp}" >/dev/null 2>&1
dir="${tmp}"
fi
if [[ "${dir}" == *.apex ]]; then
trap 'cleanup_trap' EXIT
echo
echo "Recursively analyzing $dir"
echo
dir_filename=$(basename "${dir}")
tmp=$(mktemp -d -t "${dir_filename%.apex}_out_XXXXX")
deapexer extract "${dir}" "${tmp}" || { echo "Failed to deapex." && exit 1; }
dir="${tmp}"
fi
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
ENDCOLOR=$(tput sgr0)
unaligned_libs=()
echo
echo "=== ELF alignment ==="
matches="$(find "${dir}" -type f)"
IFS=$'\n'
exit_code=0

for match in $matches; do
[[ "${match}" == *".apk" ]] && echo "WARNING: doesn't recursively inspect .apk file: ${match}"
[[ "${match}" == *".apex" ]] && echo "WARNING: doesn't recursively inspect .apex file: ${match}"
[[ $(file "${match}") == *"ELF"* ]] || continue
res="$(objdump -p "${match}" | grep LOAD | awk '{ print $NF }' | head -1)"
if [[ $res =~ 2\*\*(1[4-9]|[2-9][0-9]|[1-9][0-9]{2,}) ]]; then
echo -e "${match}: ${GREEN}ALIGNED${ENDCOLOR} ($res)"
else
echo -e "${match}: ${RED}UNALIGNED${ENDCOLOR} ($res)"
unaligned_libs+=("${match}")
exit_code=1
fi
done

if [ ${#unaligned_libs[@]} -gt 0 ]; then
echo -e "${RED}Found ${#unaligned_libs[@]} unaligned libs (only arm64-v8a/x86_64 libs need to be aligned).${ENDCOLOR}"
cleanup_trap 1 # Exit with error code 1 when unaligned libs are found
elif [ -n "${dir_filename}" ]; then
echo -e "ELF Verification Successful"
fi
echo "====================="
cleanup_trap 0 # Exit with code 0 only if no unaligned libs were found
Loading