#!/sbin/sh # Minimal MicroG installer # By FriendlyNeighborhoodShane # Based on work by osm0sis @ xda-developers (Thanks!) # # Copyright 2018-2020 FriendlyNeighborhoodShane # Distributed under the terms of the GNU GPL v3 exec 3>&1; exec 1>&2; outfd="/proc/self/fd/$2"; zipfile="$3"; ps | grep zygote | grep -v grep >/dev/null && bootmode=true || bootmode=false; $bootmode || ps -A 2>/dev/null | grep zygote | grep -v grep >/dev/null && bootmode=true; if $bootmode; then ui_print() { echo "$1" >&3; }; else ui_print() { echo "ui_print $1" >> "$outfd"; echo "ui_print" >> "$outfd"; }; fi; log() { echo "$1"; } $bootmode || mount -o bind /dev/urandom /dev/random; select_word() { select_term="$1"; while read -r select_line; do select_current=0; select_found=""; for select_each in $select_line; do select_current="$(( select_current + 1 ))"; [ "$select_current" = "$select_term" ] && { select_found="yes"; break; } done; [ "$select_found" = "yes" ] && echo "$select_each"; done; } file_getprop() { grep "^$2" "$1" | head -n1 | select_word 1 | cut -d= -f2; } abort() { ui_print " "; ui_print "!!! FATAL ERROR: $1"; ui_print " "; ui_print "Stopping installation and Uninstalling..."; uninstall_pack; [ -d "$filedir" ] && rm -rf "$filedir"; [ -d "$bbdir" ] && rm -rf "$bbdir"; $bootmode || { if [ "$sysroot" ]; then umount "/$sysroot"; else umount "/system"; fi; } sync; ui_print " "; ui_print "Installation failed!"; ui_print " "; exit 1; } ui_print " "; ui_print "-- Minimal MicroG Installer --"; ui_print "-- The Essentials only MicroG pack --"; modname="MinMicroG"; log " "; log "Zip File is $zipfile"; log "Bootmode is $bootmode"; $bootmode || { [ -e "/system" ] && mount -o ro /system; [ -e "/system_root" ] && mount -o ro /system_root; [ -e "/mnt/system" ] && mount -o ro /mnt/system; mount /data; } [ -e "/system/system/build.prop" ] && sysroot="system"; [ -e "/system_root/system/build.prop" ] && sysroot="system_root"; [ -e "/mnt/system/system/build.prop" ] && sysroot="mnt/system"; [ -f "/$sysroot/system/build.prop" ] || abort "Could not find a ROM in /$sysroot"; bbdir="/tmp/busybox"; $bootmode || { for bb in /data/adb/magisk/busybox; do [ -f "$bb" ] && magiskbb="$bb"; done; [ "$magiskbb" ] && { ui_print " "; ui_print "Setting up busybox..."; mkdir -p "$bbdir"; "$magiskbb" --install -s "$bbdir/"; export PATH="$bbdir:$PATH"; log "Shell path set to $PATH"; } } for bin in chcon chmod chown cp cut df du echo find grep head mkdir mount ps rm sed tail touch umount unzip; do command -v "$bin" >/dev/null || abort "No $bin available"; done; $bootmode && filedir="/dev/tmp/$modname" || filedir="/tmp/$modname"; tmplibdir="$filedir/tmplibdir"; $bootmode && forcesys=no; case "$(basename "$zipfile")" in *system*|*System*|*SYSTEM*) forcesys=yes; ui_print " "; ui_print "WARNING: Forcing a system action!"; ;; esac; case "$(basename "$zipfile")" in *uninstall*|*Uninstall*|*UNINSTALL*) action=uninstallation; ;; *) action=installation; ;; esac; abi="$(file_getprop /$sysroot/system/build.prop ro.product.cpu.abi)"; case "$abi" in arm64*) arch=arm64; libarches="arm64-v8a armeabi-v7a armeabi"; ;; arm*) arch=arm; libarches="armeabi-v7a armeabi"; ;; x86_64*) arch=x86_64; libarches="x86_64 x86 armeabi-v7a armeabi"; ;; x86*) arch=x86; libarches="x86 armeabi-v7a armeabi"; ;; mips64*) arch=mips64; libarches="mips64 mips"; ;; mips*) arch=mips; libarches="mips"; ;; *) abort "Could not recognise architecture: $abi"; ;; esac; sdk="$(file_getprop /$sysroot/system/build.prop ro.build.version.sdk)"; [ "$sdk" ] || abort "Could not find SDK"; [ "$sdk" -gt 0 ] || abort "Could not recognise SDK: $sdk"; sizecheck() { for realsizeobject in $1; do sizeobject="$realsizeobject"; break; done; [ -e "$sizeobject" ] || { echo 0; return 0; } objectsize="$(du -s "$sizeobject" | select_word 1)"; libsize=0; case "$sizeobject" in *.apk) apkunzip="$(unzip -l "$sizeobject" "lib/*/lib*.so")"; if echo "$apkunzip" | grep -q "lib/.*/lib.*.so"; then for archlib in $libarches; do if echo "$apkunzip" | grep -q "lib/$archlib/lib.*.so"; then libsizeb=0; for entry in $(unzip -l "$sizeobject" | grep "lib/$archlib/lib.*.so" | select_word 1); do libsizeb="$(( libsizeb + entry ))"; done; libsize="$(( libsizeb / 1024 + 1 ))"; break; fi; done; fi; ;; esac; echo "$(( objectsize + libsize ))"; } remove() { removalobject="$1"; backupobject="$2"; if [ "$sdk" -lt 21 ]; then [ "$(basename "$(dirname "$removalobject")").apk" = "$(basename "$removalobject")" ] && { removalobject="$(dirname "$(dirname "$removalobject")")/$(basename "$removalobject")"; backupobject="$(dirname "$(dirname "$backupobject")")/$(basename "$backupobject")"; } fi; [ "$(basename "$(dirname "$removalobject")").apk" = "$(basename "$removalobject")" ] && { removalobject="$(dirname "$removalobject")"; backupobject="$(dirname "$backupobject")"; } [ -e "$removalobject" ] || return 0; mkdir -p "$(dirname "$backupobject")"; cp -rf "$removalobject" "$backupobject"; if [ -e "$backupobject" ]; then log "BACKUPER: Object backed up ($removalobject)"; else log "ERROR: Could not backup ($removalobject)"; fi; rm -rf "$removalobject" || { log "ERROR: Could not remove ($removalobject)"; return 1; } if [ -e "$removalobject" ]; then log "ERROR: Could not remove ($removalobject)"; return 1; else log "REMOVER: Object removed ($removalobject)"; fi; } debloat() { debloatobject="$1"; debloatingobject="$2"; if [ "$sdk" -lt 21 ]; then [ "$(basename "$(dirname "$debloatobject")").apk" = "$(basename "$debloatobject")" ] && { debloatobject="$(dirname "$(dirname "$debloatobject")")/$(basename "$debloatobject")"; debloatingobject="$(dirname "$(dirname "$debloatingobject")")/$(basename "$debloatingobject")"; } fi; [ "$(basename "$(dirname "$debloatobject")").apk" = "$(basename "$debloatobject")" ] && debloatobject="$(dirname "$debloatobject")"; [ -e "$debloatobject" ] || return 0; mkdir -p "$(dirname "$debloatingobject")"; if [ "$(basename "$(dirname "$debloatingobject")").apk" = "$(basename "$debloatingobject")" ]; then if touch "$(dirname "$debloatingobject")/.replace"; then log "DEBLOATER: Object directory debloated ($debloatobject)"; else log "ERROR: Could not create replace file for object $debloatobject"; return 1; fi; elif [ -d "$debloatobject" ]; then mkdir -p "$debloatingobject"; if touch "$debloatingobject/.replace"; then log "DEBLOATER: directory debloated ($debloatobject)"; else log "ERROR: Could not create replace file for directory $debloatobject"; return 1; fi; else if echo "# This is a dummy for debloating" > "$debloatingobject"; then log "DEBLOATER: Object dummy debloated ($debloatobject)"; else log "ERROR: Could not create dummy file for $debloatobject"; return 1; fi; fi; } uninstall() { uninstallobject="$1"; if [ "$sdk" -lt 21 ]; then [ "$(basename "$(dirname "$uninstallobject")").apk" = "$(basename "$uninstallobject")" ] && uninstallobject="$(dirname "$(dirname "$uninstallobject")")/$(basename "$uninstallobject")"; fi; [ "$(basename "$(dirname "$uninstallobject")").apk" = "$(basename "$uninstallobject")" ] && uninstallobject="$(dirname "$uninstallobject")"; [ -e "$uninstallobject" ] || return 0; rm -rf "$uninstallobject" || { log "ERROR: Object not uninstalled ($uninstallobject)"; return 1; } if [ -e "$uninstallobject" ]; then log "ERROR: Object not uninstalled ($uninstallobject)"; return 1; else log "UNINSTALLER: Object uninstalled ($uninstallobject)"; fi; } install_dest() { for realobject in $1; do object="$realobject"; break; done; destobject="$2"; [ -e "$object" ] || { log "ERROR: Object not found ($object)"; return 1; } if [ "$sdk" -lt 21 ]; then [ "$(basename "$(dirname "$destobject")").apk" = "$(basename "$destobject")" ] && destobject="$(dirname "$(dirname "$destobject")")/$(basename "$destobject")"; fi; mkdir -p "$(dirname "$destobject")"; cp -rf "$object" "$destobject" || abort "Could not install $destobject"; if [ -e "$destobject" ]; then log "INSTALLER: Object installed ($object to $destobject)"; else abort "Could not install $destobject"; fi; case "$destobject" in *.apk) install_lib "$destobject"; ;; esac; } install_lib() { libobject="$1"; mkdir -p "$tmplibdir"; unzipout="$(unzip -l "$libobject" "lib/*/lib*.so")"; echo "$unzipout" | grep -q "lib/.*/lib.*.so" || return 0; for archlib in $libarches; do if echo "$unzipout" | grep -q "lib/$archlib/lib.*.so"; then case "$archlib" in *arm64*) log "INSTALLER: Installing arm64 libs ($libobject)"; libdir=lib64; libarch=arm64; ;; *arm*) log "INSTALLER: Installing arm libs ($libobject)"; libdir=lib; libarch=arm; ;; *x86_64*) log "INSTALLER: Installing x86_64 libs ($libobject)"; libdir=lib64; libarch=x86_64; ;; *x86*) log "INSTALLER: Installing x86 libs ($libobject)"; libdir=lib; libarch=x86; ;; *mips64*) log "INSTALLER: Installing mips64 libs ($libobject)"; libdir=lib64; libarch=mips64; ;; *mips*) log "INSTALLER: Installing mips libs ($libobject)"; libdir=lib; libarch=mips; ;; esac; if [ "$sdk" -lt 21 ]; then libdest="$(dirname "$(dirname "$libobject")")/$libdir"; else libdest="$(dirname "$libobject")/lib/$libarch"; fi; unzip -oq "$libobject" "lib/$archlib/lib*.so" -d "$tmplibdir"; mkdir -p "$libdest"; for lib in "$tmplibdir/lib/$archlib"/lib*.so; do cp -rf "$lib" "$libdest/$(basename "$lib")" || abort "Could not Install $lib for $libobject"; if [ -f "$libdest/$(basename "$lib")" ]; then log "INSTALLER: Installed library ($lib to $libdest)"; else abort "Could not Install $lib for $libobject"; fi; done; break; fi; done; rm -rf "$tmplibdir"; } uninstall_pack() { if [ "$magisk" = "yes" ]; then rm -rf "$root" || { log " "; log "Could not delete Magisk root ($root)"; } elif [ "$magisk" = "no" ]; then for thing in $stuff_uninstall; do [ "$thing" ] && uninstall "$root/$thing"; done; fi; } perm() { uid="$1"; gid="$2"; dmod="$3"; fmod="$4"; permobject="$5"; [ -e "$permobject" ] || return 0; chown -R "$uid:$gid" "$permobject" || chown -R "$uid.$gid" "$permobject"; find "$permobject" -type d -exec chmod "$dmod" {} +; find "$permobject" -type f -exec chmod "$fmod" {} +; } rm -rf "$filedir"; mkdir -p "$filedir"; unzip -o "$zipfile" "defconf" -d "$filedir/"; [ -f "$filedir/defconf" ] || abort "Could not find a default config"; . "$filedir/defconf" || abort "Could not execute default config"; moddir="/data/media/0/$modname"; backupdir="$moddir/Backup"; ui_print " "; ui_print "Package: $variant"; ui_print "Version: $ver"; ui_print "Release date: $date"; ui_print " "; ui_print "Using architecture: $arch"; ui_print "Using SDK level: $sdk"; ui_print "Sysroot is on /$sysroot"; if [ "$sdk" -lt "$minsdk" ]; then ui_print " "; ui_print "WARNING: Using an old Android"; ui_print "Full compatibility not guaranteed"; fi; ui_print " "; ui_print "Mounting..."; if [ -e "/data/adb/magisk" ] && [ "$forcesys" != "yes" ]; then $bootmode && modulesdir="/data/adb/modules_update" || modulesdir="/data/adb/modules"; root="$modulesdir/$modname"; magisk=yes; log "Using $modulesdir"; [ -d "$modulesdir" ] || { mkdir -p "$modulesdir"; perm 0 0 0755 0644 "$modulesdir"; } else if [ "$sysroot" ]; then mount -o rw,remount /$sysroot; mount -o rw,remount /$sysroot /$sysroot; else mount -o rw,remount /system; mount -o rw,remount /system /system; fi; root="/$sysroot"; magisk=no; log "Mounted /$sysroot/system RW"; fi; if [ "$action" = "installation" ]; then ui_print " "; ui_print "Extracting files..."; mkdir -p "$filedir"; unzip -o "$zipfile" -d "$filedir" || abort "Could not unzip $zipfile"; pre_install_actions; ui_print " "; ui_print "Cleaning up..."; log "Removing duplicates"; uninstall_pack; log "Debloating"; if [ "$magisk" = "yes" ]; then for thing in $stuff_debloat $stuff_uninstall; do [ "$thing" ] && debloat "/$sysroot/$thing" "$root/$thing"; done; elif [ "$magisk" = "no" ]; then for thing in $stuff_debloat; do [ "$thing" ] && remove "/$sysroot/$thing" "$backupdir/$thing"; done; fi; [ -d "$backupdir" ] && { perm 1023 1023 775 664 "$backupdir"; chcon -hR 'u:object_r:media_rw_data_file:s0' "$backupdir"; } ui_print " "; ui_print "Doing size checks..."; packsize=0; for thing in defconf $stuff; do [ "$thing" ] && packsize="$(( packsize + $(sizecheck "$filedir/$thing") ))"; done; for thing in $stuff_arch; do [ "$thing" ] && packsize="$(( packsize + $(sizecheck "$filedir/$(dirname "$thing")/*-$arch-*/$(basename "$thing")") ))"; done; for thing in $stuff_sdk; do [ "$thing" ] && packsize="$(( packsize + $(sizecheck "$filedir/$(dirname "$thing")/*-$sdk-*/$(basename "$thing")") ))"; done; for thing in $stuff_arch_sdk; do [ "$thing" ] && packsize="$(( packsize + $(sizecheck "$filedir/$(dirname "$thing")/*-$arch-*-$sdk-*/$(basename "$thing")") ))"; done; packsizem="$(( packsize / 1024 + 1 ))"; log "Pack size is $packsizem"; if [ "$magisk" = "yes" ]; then datfreem="$(( $(df -Pk "/data" | tail -n 1 | select_word 4) / 1024 ))"; log "Free data space is $datfreem"; [ "$datfreem" -lt "$packsizem" ] && abort "Not enough free space in your data!"; elif [ "$magisk" = "no" ]; then sysfreem="$(( $(df -Pk "/$sysroot/system" | tail -n 1 | select_word 4) / 1024 ))"; log "Free system space is $sysfreem"; [ "$sysfreem" -lt "$packsizem" ] && abort "Not enough free space in your system!"; fi; ui_print " "; ui_print "Installing $modname to $root..."; mkdir -p "$root"; log " "; log "Installing generic stuff"; for thing in $stuff; do [ "$thing" ] && install_dest "$filedir/$thing" "$root/$thing"; done; log " "; log "Installing Arch dependant stuff for $arch"; for thing in $stuff_arch; do [ "$thing" ] && install_dest "$filedir/$(dirname "$thing")/*-$arch-*/$(basename "$thing")" "$root/$thing"; done; log " "; log "Installing SDK dependant stuff for SDK $sdk"; for thing in $stuff_sdk; do [ "$thing" ] && install_dest "$filedir/$(dirname "$thing")/*-$sdk-*/$(basename "$thing")" "$root/$thing"; done; log " "; log "Installing Arch and SDK dependant stuff for $arch and SDK $sdk"; for thing in $stuff_arch_sdk; do [ "$thing" ] && install_dest "$filedir/$(dirname "$thing")/*-$arch-*-$sdk-*/$(basename "$thing")" "$root/$thing"; done; log " "; log "Executing other actions"; if [ "$magisk" = "yes" ]; then [ "$modprop" ] && { echo "$modprop" > "$root/module.prop" || abort "Could not create module.prop in $root"; } touch "$root/auto_mount" || abort "Could not create auto_mount in $root"; if $bootmode && [ "$modulesdir" = "/data/adb/modules_update" ]; then modmnt="/data/adb/modules"; mkdir -p "$modmnt/$modname"; touch "$modmnt/$modname/update" || abort "Could not create update in $modmnt/$modname"; [ "$modprop" ] && { echo "$modprop" > "$modmnt/$modname/module.prop" || abort "Could not create module.prop in $modmnt/$modname"; } fi; fi; ui_print " "; ui_print "Setting permissions..."; if [ "$magisk" = "yes" ]; then find "$root" -maxdepth 1 -exec chmod 0755 {} +; fi; for thing in $stuff_perm; do case "$thing" in */bin*|*/xbin*|*/lib*) perm 0 2000 0755 0777 "$root/$thing"; ;; *) perm 0 0 0755 0644 "$root/$thing"; ;; esac; chcon -hR 'u:object_r:system_file:s0' "$root/$thing"; done; post_install_actions; fi; if [ "$action" = "uninstallation" ]; then pre_uninstall_actions; ui_print " "; ui_print "Uninstalling $modname from $root..."; uninstall_pack; post_uninstall_actions; fi; ui_print " "; ui_print "Unmounting..."; $bootmode || { if [ "$sysroot" ]; then umount "/$sysroot"; else umount /system; fi; } rm -rf "$filedir"; [ -d "$bbdir" ] && rm -rf "$bbdir"; sync; ui_print " "; ui_print "Done!"; ui_print " "; exit 0;