Created
September 24, 2025 10:08
-
-
Save manwithsteelnerves/4acd7ada0013484375f762caaf46dd71 to your computer and use it in GitHub Desktop.
Script for checking 16KB page alignment (for Google Play Requirement)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # Colors | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| BLUE='\033[0;34m' | |
| YELLOW='\033[1;33m' | |
| NC='\033[0m' # No Color | |
| # ============================= Helpers ====================================== | |
| get_arch_from_objdump() { | |
| local so_file="$1" | |
| local arch_line | |
| arch_line=$(objdump -f "$so_file" 2>/dev/null | awk -F: '/architecture/ {print $2}' | tr '[:upper:]' '[:lower:]') | |
| case "$arch_line" in | |
| *aarch64*) echo "ARM64" ;; | |
| *x86-64*) echo "x86_64" ;; | |
| *i386*) echo "x86" ;; | |
| *arm*) echo "ARM v7" ;; | |
| *) echo "unknown" ;; | |
| esac | |
| } | |
| check_so_alignment() { | |
| local so_file="$1" relative_path="$2" | |
| if [[ ! -f "$so_file" ]]; then | |
| echo "ERROR|File not found|❌|0B|$relative_path|Unknown" | |
| return 1 | |
| fi | |
| local objdump_p | |
| if ! objdump_p=$(objdump -p "$so_file" 2>/dev/null); then | |
| echo "ERROR|objdump failed|❌|0B|$relative_path|Unknown" | |
| return 1 | |
| fi | |
| local arch | |
| arch=$(get_arch_from_objdump "$so_file") | |
| if [[ "$arch" == "ARM v7" ]]; then | |
| echo "PASS|ARM v7 - 16KB not required|✅|N/A|$relative_path|$arch" | |
| return 0 | |
| fi | |
| local max_exp | |
| max_exp=$(echo "$objdump_p" \ | |
| | grep -E "^ *LOAD" \ | |
| | grep -oE "align 2\*\*[0-9]+" \ | |
| | sed 's/align 2\*\*//' \ | |
| | sort -nr \ | |
| | head -1) | |
| if [[ -z "$max_exp" ]]; then | |
| echo "ERROR|Unknown alignment|❌|Unknown|$relative_path|$arch" | |
| return 1 | |
| fi | |
| local alignment_disp | |
| if (( max_exp >= 10 )); then | |
| local kb=$(( 1 << (max_exp - 10) )) | |
| alignment_disp="${kb}KB" | |
| else | |
| local bytes=$(( 1 << max_exp )) | |
| alignment_disp="${bytes}B" | |
| fi | |
| if (( max_exp >= 14 )); then | |
| echo "PASS|>=16KB aligned|✅|${alignment_disp}|$relative_path|$arch" | |
| return 0 | |
| else | |
| echo "FAIL|Need 16KB alignment|❌|${alignment_disp}|$relative_path|$arch" | |
| return 1 | |
| fi | |
| } | |
| # ============================= Table/UI ====================================== | |
| print_table_header() { | |
| printf "${BLUE}%-8s %-50s %-12s %-12s %-s${NC}\n" "Status" "File Path" "Architecture" "Alignment" "Notes" | |
| printf "%s\n" "$(printf '=%.0s' {1..120})" | |
| } | |
| print_table_row() { | |
| local status="$1" filepath="$2" arch="$3" alignment="$4" notes="$5" | |
| local color="" | |
| case "$status" in | |
| "✅") color="${GREEN}" ;; | |
| "❌") color="${RED}" ;; | |
| *) color="${NC}" ;; | |
| esac | |
| printf "${color}%-8s${NC} %-50s %-12s %-12s %-s\n" "$status" "$filepath" "$arch" "$alignment" "$notes" | |
| } | |
| process_results() { | |
| local results=("$@") | |
| local total_so=0 aligned_so=0 failed_so=0 | |
| local passes=() fails=() | |
| for result in "${results[@]}"; do | |
| [[ -z "$result" ]] && continue | |
| total_so=$((total_so + 1)) | |
| IFS='|' read -r status_type notes symbol alignment filepath arch <<< "$result" | |
| if [[ "$status_type" == "PASS" ]]; then | |
| aligned_so=$((aligned_so + 1)) | |
| passes+=("$symbol|$filepath|$arch|$alignment|$notes") | |
| else | |
| failed_so=$((failed_so + 1)) | |
| fails+=("$symbol|$filepath|$arch|$alignment|$notes") | |
| fi | |
| done | |
| # Print grouped table | |
| if [[ ${#passes[@]} -gt 0 ]]; then | |
| echo -e "\n${GREEN}✅ Compatible Libraries${NC}" | |
| print_table_header | |
| for row in "${passes[@]}"; do | |
| IFS='|' read -r symbol filepath arch alignment notes <<< "$row" | |
| print_table_row "$symbol" "$filepath" "$arch" "$alignment" "$notes" | |
| done | |
| fi | |
| if [[ ${#fails[@]} -gt 0 ]]; then | |
| echo -e "\n${RED}❌ Not Compatible Libraries${NC}" | |
| print_table_header | |
| for row in "${fails[@]}"; do | |
| IFS='|' read -r symbol filepath arch alignment notes <<< "$row" | |
| print_table_row "$symbol" "$filepath" "$arch" "$alignment" "$notes" | |
| done | |
| fi | |
| echo "" | |
| printf "%s\n" "$(printf '=%.0s' {1..120})" | |
| echo -e "${BLUE}📊 SUMMARY${NC}" | |
| echo "Total .so files: $total_so" | |
| echo -e "16KB Aligned (>=): ${GREEN}$aligned_so${NC}" | |
| echo -e "Not aligned: ${RED}$failed_so${NC}" | |
| if [[ $failed_so -eq 0 ]]; then | |
| echo -e "\n${GREEN}🎉 All .so files are properly aligned!${NC}" | |
| else | |
| echo -e "\n${RED}⚠️ Some .so files need alignment fixes${NC}" | |
| fi | |
| } | |
| # ============================= Processors ===================================== | |
| process_apk() { | |
| local apk_file="$1" | |
| local temp_dir | |
| echo -e "${BLUE}📱 Processing APK: $apk_file${NC}" | |
| echo "=================================================" | |
| temp_dir=$(mktemp -d) | |
| trap "rm -rf '$temp_dir'" RETURN | |
| echo "🔓 Extracting APK..." | |
| if ! unzip -q "$apk_file" -d "$temp_dir"; then | |
| echo -e "${RED}❌ Failed to extract APK file${NC}" | |
| return 1 | |
| fi | |
| local results=() | |
| while IFS= read -r -d '' so_file; do | |
| local relative_path=${so_file#$temp_dir/} | |
| results+=("$(check_so_alignment "$so_file" "$relative_path")") | |
| done < <(find "$temp_dir" -type f -name "*.so" -print0) | |
| if [[ ${#results[@]} -eq 0 ]]; then | |
| echo -e "${YELLOW}⚠️ No .so files found in APK${NC}" | |
| return 0 | |
| fi | |
| process_results "${results[@]}" | |
| } | |
| process_single_so() { | |
| local so_file="$1" | |
| echo -e "${BLUE}🔍 Processing single .so file: $so_file${NC}" | |
| echo "=================================================" | |
| local result | |
| result=$(check_so_alignment "$so_file" "$(basename "$so_file")") | |
| process_results "$result" | |
| } | |
| process_directory() { | |
| local dir="$1" | |
| echo -e "${BLUE}📁 Processing directory: $dir${NC}" | |
| echo "=================================================" | |
| local results=() | |
| while IFS= read -r -d '' so_file; do | |
| local relative_path=${so_file#$dir/} | |
| results+=("$(check_so_alignment "$so_file" "$relative_path")") | |
| done < <(find "$dir" -type f -name "*.so" -print0) | |
| if [[ ${#results[@]} -eq 0 ]]; then | |
| echo -e "${YELLOW}⚠️ No .so files found in directory${NC}" | |
| return 0 | |
| fi | |
| process_results "${results[@]}" | |
| } | |
| show_usage() { | |
| echo "Usage: $0 <file_or_directory>" | |
| echo "" | |
| echo "Examples:" | |
| echo " $0 app.apk" | |
| echo " $0 libfoo.so" | |
| echo " $0 /path/to/lib/dir" | |
| } | |
| # ============================= Entry & Deps =================================== | |
| check_dependencies() { | |
| local missing=() | |
| command -v objdump >/dev/null 2>&1 || missing+=("objdump (binutils)") | |
| command -v unzip >/dev/null 2>&1 || missing+=("unzip") | |
| if [[ ${#missing[@]} -gt 0 ]]; then | |
| echo -e "${RED}❌ Missing dependencies:${NC}" | |
| for dep in "${missing[@]}"; do echo " - $dep"; done | |
| exit 1 | |
| fi | |
| } | |
| main() { | |
| if [[ $# -eq 0 ]]; then | |
| show_usage; exit 1 | |
| fi | |
| local input="$1" | |
| if [[ -f "$input" ]]; then | |
| if [[ "$input" == *.apk ]]; then | |
| process_apk "$input" | |
| elif [[ "$input" == *.so ]]; then | |
| process_single_so "$input" | |
| else | |
| echo -e "${RED}❌ Unsupported file type${NC}"; exit 1 | |
| fi | |
| elif [[ -d "$input" ]]; then | |
| process_directory "$input" | |
| else | |
| echo -e "${RED}❌ Invalid input${NC}"; exit 1 | |
| fi | |
| } | |
| check_dependencies | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment