#This file is part of The Open GApps script of @mfonville. # # The Open GApps scripts are free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # These scripts are distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # alignbuild() { echo "Zipaligning APKs..." for f in $(find "$build" -name '*.apk'); do # skip zipaligning for APKs signed with apksigner, because zipalign strips its signature # see https://developer.android.com/studio/command-line/zipalign if timeout 1m apksigner verify --verbose --print-certs "$f" 2>/dev/null | grep -q "(JAR signing): false"; then continue fi mv "$f" "$f.orig" zopfli="" if [ -n "$ZIPALIGNRECOMPRESS" ]; then zopfli="-z" fi zipalign -f -p $zopfli 4 "$f.orig" "$f" rm "$f.orig" done } commonscripts() { copy "$SCRIPTS/bkup_tail.sh" "$build" EXTRACTFILES="$EXTRACTFILES bkup_tail.sh" install -d "$build/META-INF/com/google/android" echo "# Dummy file; update-binary is a shell script.">"$build/META-INF/com/google/android/updater-script" makegappsremovetxt "gapps-remove.txt" makegprop "g.prop" makeinstallersh "installer.sh" bundlebusybox if [ "$VARIANT" = "aroma" ]; then COMPRESSION="xz" # Aroma does not play nice with the busybox built-in decompressors bundlexzdec fi bundletar bundleunzip bundlezip makeupdatebinary "META-INF/com/google/android/update-binary" "busybox" "installer.sh" "$EXTRACTFILES" "$CHMODXFILES" # execute as last so that $EXTRACTFILES and $CHMODXFILES are complete bundlelicense #optionally add a LICENSE file to the package } aromascripts() { aromaupdatebinary makearomaconfig install -d "$build/META-INF/com/google/android/aroma" #not necessary, but is safe copy "$SCRIPTS/aroma-resources/fonts" "$build/META-INF/com/google/android/aroma/fonts" copy "$SCRIPTS/aroma-resources/icons" "$build/META-INF/com/google/android/aroma/icons" copy "$SCRIPTS/aroma-resources/langs" "$build/META-INF/com/google/android/aroma/langs" copy "$SCRIPTS/aroma-resources/scripts" "$build/META-INF/com/google/android/aroma/scripts" copy "$SCRIPTS/aroma-resources/themes" "$build/META-INF/com/google/android/aroma/themes" copy "$SCRIPTS/aroma-resources/ttf" "$build/META-INF/com/google/android/aroma/ttf" copy "$SCRIPTS/aroma-resources/open.png" "$build/META-INF/com/google/android/aroma" } aromaupdatebinary() { if [ -f "$build/META-INF/com/google/android/update-binary-installer" ] then rm "$build/META-INF/com/google/android/update-binary-installer" fi mv "$build/META-INF/com/google/android/update-binary" "$build/META-INF/com/google/android/update-binary-installer" copy "$SCRIPTS/aroma-resources/update-binary" "$build/META-INF/com/google/android/update-binary" } bundlebusybox() { case "$ARCH" in #Include busybox binary arm*) busyboxbin="busybox-arm";; x86*) busyboxbin="busybox-x86";; esac copy "$SCRIPTS/busybox-resources/$busyboxbin" "$build/$busyboxbin" EXTRACTFILES="$EXTRACTFILES $busyboxbin" CHMODXFILES="$CHMODXFILES $busyboxbin" } bundlexzdec() { case "$ARCH" in #Include xzdec binary arm*) xzdecbin="xzdec-arm";; x86*) xzdecbin="xzdec-x86";; esac copy "$SCRIPTS/xz-resources/$xzdecbin" "$build/$xzdecbin" EXTRACTFILES="$EXTRACTFILES $xzdecbin" CHMODXFILES="$CHMODXFILES $xzdecbin" } bundletar() { case "$ARCH" in #Include tar binary arm*) tarbin="tar-arm";; x86*) tarbin="tar-x86";; esac copy "$SCRIPTS/tar-resources/$tarbin" "$build/$tarbin" EXTRACTFILES="$EXTRACTFILES $tarbin" CHMODXFILES="$CHMODXFILES $tarbin" } bundleunzip() { case "$ARCH" in #Include unzip binary arm*) unzipbin="unzip-arm";; x86*) unzipbin="unzip-x86";; esac copy "$SCRIPTS/infozip-resources/$unzipbin" "$build/$unzipbin" EXTRACTFILES="$EXTRACTFILES $unzipbin" CHMODXFILES="$CHMODXFILES $unzipbin" } bundlezip() { case "$ARCH" in #Include zip binary arm*) zipbin="zip-arm";; x86*) zipbin="zip-x86";; esac copy "$SCRIPTS/infozip-resources/$zipbin" "$build/$zipbin" EXTRACTFILES="$EXTRACTFILES $zipbin" CHMODXFILES="$CHMODXFILES $zipbin" } bundlelicense() { if [ -n "$OPENGAPPSLICENSEFILE" ] && [ -e "$OPENGAPPSLICENSEFILE" ]; then echo "INFO: using $OPENGAPPSLICENSEFILE as LICENSE file" copy "$OPENGAPPSLICENSEFILE" "$build/LICENSE" elif [ -e "LICENSE" ]; then copy "LICENSE" "$build/LICENSE" fi } compressapp() { compression="$COMPRESSION" compressioncompathack "$2" case "$compression" in xz) checktools xz csuf=".xz" compress() { XZ_OPT='-9e -C crc32 -T0' tar --remove-files -cJf "$1.tar.xz" "$1" } ;; lz) checktools lzip csuf=".lz" compress() { tar --remove-files -cf - "$1" | lzip -m 273 -s 128MiB -o "$1.tar" #.lz is added by lzip; specify the compression parameters manually to get good results } ;; none) csuf="" compress() { tar --remove-files -cf "$1.tar" "$1" } ;; *) echo "ERROR: Unsupported compression method! Aborting..."; exit 1;; esac hash="$(tar -cf - "$2" | md5sum | cut -f1 -d' ')" if [ -f "$CACHE/$hash.tar$csuf" ]; then #we have this compressed app in cache echo "Fetching $1$2 from the cache" rm -rf "$2" #remove the folder touch -a "$CACHE/$hash.tar$csuf" #mark this cache object as recently accessed cp "$CACHE/$hash.tar$csuf" "$2.tar$csuf" #copy from the cache else if [ -n "$3" ] && [ -n "$4" ]; then echo "Thread: $3 | FreeRAM: $4 | Compressing Package: $1$2" else echo "Compressing Package: $1$2" fi compress "$2" if [ $? != 0 ]; then echo "ERROR: compressing $1$2 failed, aborting." exit 1 fi cp "$2.tar$csuf" "$CACHE/$hash.tar$csuf" #copy into the cache fi touch -d "2008-02-28 21:33:46.000000000 +0100" "$2.tar$csuf" sync } createzip() { echo "INFO: Total size uncompressed applications: $(du -hs "$build" | awk '{ print $1 }')" find "$build" -exec touch -d "2008-02-28 21:33:46.000000000 +0100" {} \; cd "$build" MEMORY_MIN=800000 # Minimum of RAM required (for single thread) on x86_64 machine based on XZ's documentation (which is a comparable algorithm to lzip) THREADS="$(($(nproc)))" if ! grep -q "MemAvailable:" /proc/meminfo; then MEMORY=0 else MEMORY="$(($(grep "MemAvailable:" /proc/meminfo | awk '{print $2}') / 4))" fi if [ $MEMORY = 0 ] || [ $MEMORY -lt $MEMORY_MIN ]; then echo "WARNING: Can't establish if enough free memory is available: parallel compression mode disabled." MEMORY=0 THREADS=1 fi pidlist="" for d in $(ls -d */ | grep -v "META-INF"); do #notice that d will end with a slash, ls is safe here because there are no directories with spaces cd "$build/$d" for f in $(ls); do # ls is safe here because there are no directories with spaces apk="$(find "$f/" -name "*.apk" -type f | head -n 1)" # we assume the classes*.dex are around the same size in all APK variants if [ -f "$apk" ] && ! (unzip -ql "$apk" | grep -q "META-INF/MANIFEST.MF" && unzip -p "$apk" "META-INF/MANIFEST.MF" | grep -q "$classes.dex"); then printf "%s\t%s\t%d\n" "$f" "odex" "$(($(echo "$(unzip -ql "$apk" "classes*.dex" | tail -n 1)" | awk '{print $1"*(("$2"/2)+2)/1024"}')))" >> "$build/app_sizes.txt" # estimation heuristic: size-dexfiles * ((#-dexfiles/2)+2); bytes -> KiB fi for g in $(ls "$f"); do foldersize="$(du -ck "$f/$g/" | tail -n1 | awk '{ print $1 }')" printf "%s\t%s\t%d\n" "$f" "$g" "$foldersize" >> "$build/app_sizes.txt" done # Use parallel mode only if we have memory metric and have more than 1 CPU if [ $THREADS -gt 1 ] && [ $MEMORY -gt 0 ]; then # Wait if we reached RAM or THREADS limit tries=0; while true; do # Count still running compressapp instances threads=0; for p in $pidlist; do test -d /proc/$p && threads=$((threads+1)); done memory=$(grep "MemAvailable:" /proc/meminfo | awk '{print $2}') # Check if reached our limits (3/4 of RAM or THREADS), wait if we are if [ $threads -ge $THREADS ] || [ $MEMORY -ge $memory ] || [ $memory -lt $MEMORY_MIN ]; then sleep 5 # Update tries counter tries=$((tries+1)) # If we are trying for more then 180*5 seconds, we bail out (in case machine is to low on memory or CPU we won't run forever!) if [ $tries -gt 180 ]; then echo "ERROR: Seems like this machine is too slow or was unable to collect enought usable memory for compression, aborting." exit 1 fi continue else break fi done # Spawn compressapp thread compressapp "$d" "$f" "$threads" "$memory" & # Collect resulting PID pidlist="$pidlist $!" else # Call compressapp compressapp "$d" "$f" fi done done for p in $pidlist; do wait $p; done echo "INFO: Total size compressed applications: $(du -hs "$build" | awk '{ print $1 }')" unsignedzip="$BUILD/$ARCH/$API/$VARIANT.zip" if [ -n "$OUTFILE" ]; then signedzip="$( eval "echo \"$OUTFILE\"")" else signedzip="$OUTFOLDER/open_gapps-$ARCH-$PLATFORM-$VARIANT-$DATE-UNOFFICIAL.zip" fi if [ -f "$unsignedzip" ]; then rm "$unsignedzip" fi cd "$build" echo "Packaging and signing $signedzip..." zip -q -r -D -X -$ZIPCOMPRESSIONLEVEL "$unsignedzip" ./* #don't doublequote zipfolders, contains multiple (safe) arguments cd "$TOP" signzip } signzip() { install -d "$(dirname "$signedzip")" if [ -f "$signedzip" ] then rm "$signedzip" fi if [ -z "$CERTIFICATEFILE" ] || [ ! -e "$CERTIFICATEFILE" ]; then unset CERTIFICATEFILE else echo "INFO: using $CERTIFICATEFILE as certificate file" fi if [ -z "$KEYFILE" ] || [ ! -e "$KEYFILE" ]; then unset KEYFILE else echo "INFO: using $KEYFILE as cryptographic key file" fi if [ -z "$TMPSIGNDIR" ] || [ ! -d "$TMPSIGNDIR" ]; then unset TMPSIGNCMD else TMPSIGNCMD="-Djava.io.tmpdir=$TMPSIGNDIR" echo "INFO: using $TMPSIGNDIR as temporary directory to sign files" fi if java $TMPSIGNCMD -jar "$SCRIPTS/zipsigner-resources/zipsigner-"*.jar $CERTIFICATEFILE $KEYFILE "$unsignedzip" "$signedzip"; then #if signing did succeed rm "$unsignedzip" else rm "$signedzip" echo "ERROR: Creating Flashable ZIP-file failed, unsigned file can be found at $unsignedzip" exit 1 fi echo "SUCCESS: Built Open GApps variation $VARIANT with API $API level for $ARCH as $signedzip" }