1cd45b53b1
Some devices (mainly new Samsung phones we're talking here...) using A only system-as-root refuse to load ramdisk when booted with boot no matter what we do. With many A only system-as-root devices, even though their boot image is kernel only, we can still be able to add a ramdisk section into the image and force the kernel to use it as rootfs. However the bootloader on devices like the S10 simply does not load anything within boot image into memory other than the kernel. This gives as the only option is to install Magisk on the recovery partition. This commits adds proper support for these kind of scenarios.
427 lines
12 KiB
Bash
427 lines
12 KiB
Bash
##########################################################################################
|
|
#
|
|
# Magisk General Utility Functions
|
|
# by topjohnwu
|
|
#
|
|
# Used everywhere in Magisk
|
|
#
|
|
##########################################################################################
|
|
|
|
##########
|
|
# Presets
|
|
##########
|
|
|
|
#MAGISK_VERSION_STUB
|
|
|
|
# Detect whether in boot mode
|
|
[ -z $BOOTMODE ] && BOOTMODE=false
|
|
$BOOTMODE || ps | grep zygote | grep -qv grep && BOOTMODE=true
|
|
$BOOTMODE || ps -A 2>/dev/null | grep zygote | grep -qv grep && BOOTMODE=true
|
|
|
|
# Presets
|
|
MAGISKTMP=/sbin/.magisk
|
|
NVBASE=/data/adb
|
|
[ -z $TMPDIR ] && TMPDIR=/dev/tmp
|
|
|
|
# Bootsigner related stuff
|
|
BOOTSIGNERCLASS=a.a
|
|
BOOTSIGNER="/system/bin/dalvikvm -Xnodex2oat -Xnoimage-dex2oat -cp \$APK \$BOOTSIGNERCLASS"
|
|
BOOTSIGNED=false
|
|
|
|
###################
|
|
# Helper Functions
|
|
###################
|
|
|
|
ui_print() {
|
|
$BOOTMODE && echo "$1" || echo -e "ui_print $1\nui_print" >> /proc/self/fd/$OUTFD
|
|
}
|
|
|
|
toupper() {
|
|
echo "$@" | tr '[:lower:]' '[:upper:]'
|
|
}
|
|
|
|
grep_cmdline() {
|
|
local REGEX="s/^$1=//p"
|
|
cat /proc/cmdline | tr '[:space:]' '\n' | sed -n "$REGEX" 2>/dev/null
|
|
}
|
|
|
|
grep_prop() {
|
|
local REGEX="s/^$1=//p"
|
|
shift
|
|
local FILES=$@
|
|
[ -z "$FILES" ] && FILES='/system/build.prop'
|
|
sed -n "$REGEX" $FILES 2>/dev/null | head -n 1
|
|
}
|
|
|
|
getvar() {
|
|
local VARNAME=$1
|
|
local VALUE=
|
|
VALUE=`grep_prop $VARNAME /sbin/.magisk/config /data/.magisk /cache/.magisk`
|
|
[ ! -z $VALUE ] && eval $VARNAME=\$VALUE
|
|
}
|
|
|
|
is_mounted() {
|
|
grep -q " `readlink -f $1` " /proc/mounts 2>/dev/null
|
|
return $?
|
|
}
|
|
|
|
abort() {
|
|
ui_print "$1"
|
|
$BOOTMODE || recovery_cleanup
|
|
exit 1
|
|
}
|
|
|
|
resolve_vars() {
|
|
MAGISKBIN=$NVBASE/magisk
|
|
POSTFSDATAD=$NVBASE/post-fs-data.d
|
|
SERVICED=$NVBASE/service.d
|
|
}
|
|
|
|
######################
|
|
# Environment Related
|
|
######################
|
|
|
|
setup_flashable() {
|
|
# Preserve environment varibles
|
|
OLD_PATH=$PATH
|
|
ensure_bb
|
|
$BOOTMODE && return
|
|
if [ -z $OUTFD ] || readlink /proc/$$/fd/$OUTFD | grep -q /tmp; then
|
|
# We will have to manually find out OUTFD
|
|
for FD in `ls /proc/$$/fd`; do
|
|
if readlink /proc/$$/fd/$FD | grep -q pipe; then
|
|
if ps | grep -v grep | grep -q " 3 $FD "; then
|
|
OUTFD=$FD
|
|
break
|
|
fi
|
|
fi
|
|
done
|
|
fi
|
|
}
|
|
|
|
ensure_bb() {
|
|
if [ -x $MAGISKTMP/busybox/busybox ]; then
|
|
[ -z $BBDIR ] && BBDIR=$MAGISKTMP/busybox
|
|
elif [ -x $TMPDIR/bin/busybox ]; then
|
|
[ -z $BBDIR ] && BBDIR=$TMPDIR/bin
|
|
else
|
|
# Construct the PATH
|
|
[ -z $BBDIR ] && BBDIR=$TMPDIR/bin
|
|
mkdir -p $BBDIR
|
|
ln -s $MAGISKBIN/busybox $BBDIR/busybox
|
|
$MAGISKBIN/busybox --install -s $BBDIR
|
|
fi
|
|
echo $PATH | grep -q "^$BBDIR" || export PATH=$BBDIR:$PATH
|
|
}
|
|
|
|
recovery_actions() {
|
|
# Make sure random don't get blocked
|
|
mount -o bind /dev/urandom /dev/random
|
|
# Unset library paths
|
|
OLD_LD_LIB=$LD_LIBRARY_PATH
|
|
OLD_LD_PRE=$LD_PRELOAD
|
|
OLD_LD_CFG=$LD_CONFIG_FILE
|
|
unset LD_LIBRARY_PATH
|
|
unset LD_PRELOAD
|
|
unset LD_CONFIG_FILE
|
|
# Force our own busybox path to be in the front
|
|
# and do not use anything in recovery's sbin
|
|
export PATH=$BBDIR:/system/bin:/vendor/bin
|
|
}
|
|
|
|
recovery_cleanup() {
|
|
export PATH=$OLD_PATH
|
|
[ -z $OLD_LD_LIB ] || export LD_LIBRARY_PATH=$OLD_LD_LIB
|
|
[ -z $OLD_LD_PRE ] || export LD_PRELOAD=$OLD_LD_PRE
|
|
[ -z $OLD_LD_CFG ] || export LD_CONFIG_FILE=$OLD_LD_CFG
|
|
ui_print "- Unmounting partitions"
|
|
umount -l /system_root 2>/dev/null
|
|
umount -l /system 2>/dev/null
|
|
umount -l /vendor 2>/dev/null
|
|
umount -l /dev/random 2>/dev/null
|
|
}
|
|
|
|
#######################
|
|
# Installation Related
|
|
#######################
|
|
|
|
find_block() {
|
|
for BLOCK in "$@"; do
|
|
DEVICE=`find /dev/block -type l -iname $BLOCK | head -n 1` 2>/dev/null
|
|
if [ ! -z $DEVICE ]; then
|
|
readlink -f $DEVICE
|
|
return 0
|
|
fi
|
|
done
|
|
# Fallback by parsing sysfs uevents
|
|
for uevent in /sys/dev/block/*/uevent; do
|
|
local DEVNAME=`grep_prop DEVNAME $uevent`
|
|
local PARTNAME=`grep_prop PARTNAME $uevent`
|
|
for BLOCK in "$@"; do
|
|
if [ "`toupper $BLOCK`" = "`toupper $PARTNAME`" ]; then
|
|
echo /dev/block/$DEVNAME
|
|
return 0
|
|
fi
|
|
done
|
|
done
|
|
return 1
|
|
}
|
|
|
|
mount_partitions() {
|
|
# Check A/B slot
|
|
SLOT=`grep_cmdline androidboot.slot_suffix`
|
|
if [ -z $SLOT ]; then
|
|
SLOT=_`grep_cmdline androidboot.slot`
|
|
[ $SLOT = "_" ] && SLOT=
|
|
fi
|
|
[ -z $SLOT ] || ui_print "- Current boot slot: $SLOT"
|
|
|
|
ui_print "- Mounting /system, /vendor"
|
|
mkdir /system 2>/dev/null
|
|
[ -f /system/build.prop ] || is_mounted /system || mount -o ro /system 2>/dev/null
|
|
if ! is_mounted /system && ! [ -f /system/build.prop ]; then
|
|
SYSTEMBLOCK=`find_block system$SLOT`
|
|
mount -o ro $SYSTEMBLOCK /system
|
|
fi
|
|
[ -f /system/build.prop ] || is_mounted /system || abort "! Cannot mount /system"
|
|
grep -qE '/dev/root|/system_root' /proc/mounts && SYSTEM_ROOT=true || SYSTEM_ROOT=false
|
|
if [ -f /system/init.rc ]; then
|
|
SYSTEM_ROOT=true
|
|
mkdir /system_root 2>/dev/null
|
|
mount --move /system /system_root
|
|
mount -o bind /system_root/system /system
|
|
fi
|
|
$SYSTEM_ROOT && ui_print "- Device is system-as-root"
|
|
if [ -L /system/vendor ]; then
|
|
mkdir /vendor 2>/dev/null
|
|
is_mounted /vendor || mount -o ro /vendor 2>/dev/null
|
|
if ! is_mounted /vendor; then
|
|
VENDORBLOCK=`find_block vendor$SLOT`
|
|
mount -o ro $VENDORBLOCK /vendor
|
|
fi
|
|
is_mounted /vendor || abort "! Cannot mount /vendor"
|
|
fi
|
|
}
|
|
|
|
get_flags() {
|
|
# override variables
|
|
getvar KEEPVERITY
|
|
getvar KEEPFORCEENCRYPT
|
|
getvar RECOVERYMODE
|
|
if [ -z $KEEPVERITY ]; then
|
|
if $SYSTEM_ROOT; then
|
|
KEEPVERITY=true
|
|
ui_print "- System-as-root, keep dm/avb-verity"
|
|
else
|
|
KEEPVERITY=false
|
|
fi
|
|
fi
|
|
if [ -z $KEEPFORCEENCRYPT ]; then
|
|
grep ' /data ' /proc/mounts | grep -q 'dm-' && FDE=true || FDE=false
|
|
[ -d /data/unencrypted ] && FBE=true || FBE=false
|
|
# No data access means unable to decrypt in recovery
|
|
if $FDE || $FBE || ! $DATA; then
|
|
KEEPFORCEENCRYPT=true
|
|
ui_print "- Encrypted data, keep forceencrypt"
|
|
else
|
|
KEEPFORCEENCRYPT=false
|
|
fi
|
|
fi
|
|
[ -z $RECOVERYMODE ] && RECOVERYMODE=false
|
|
}
|
|
|
|
find_boot_image() {
|
|
BOOTIMAGE=
|
|
if $RECOVERYMODE; then
|
|
BOOTIMAGE=`find_block recovery_ramdisk$SLOT recovery`
|
|
elif [ ! -z $SLOT ]; then
|
|
BOOTIMAGE=`find_block ramdisk$SLOT recovery_ramdisk$SLOT boot$SLOT`
|
|
else
|
|
BOOTIMAGE=`find_block ramdisk recovery_ramdisk kern-a android_boot kernel boot lnx bootimg boot_a`
|
|
fi
|
|
if [ -z $BOOTIMAGE ]; then
|
|
# Lets see what fstabs tells me
|
|
BOOTIMAGE=`grep -v '#' /etc/*fstab* | grep -E '/boot[^a-zA-Z]' | grep -oE '/dev/[a-zA-Z0-9_./-]*' | head -n 1`
|
|
fi
|
|
}
|
|
|
|
flash_image() {
|
|
# Make sure all blocks are writable
|
|
$MAGISKBIN/magisk --unlock-blocks 2>/dev/null
|
|
case "$1" in
|
|
*.gz) CMD1="$MAGISKBIN/magiskboot decompress '$1' - 2>/dev/null";;
|
|
*) CMD1="cat '$1'";;
|
|
esac
|
|
if $BOOTSIGNED; then
|
|
CMD2="$BOOTSIGNER -sign"
|
|
ui_print "- Sign image with test keys"
|
|
else
|
|
CMD2="cat -"
|
|
fi
|
|
if [ -b "$2" ]; then
|
|
local img_sz=`stat -c '%s' "$1"`
|
|
local blk_sz=`blockdev --getsize64 "$2"`
|
|
[ $img_sz -gt $blk_sz ] && return 1
|
|
eval $CMD1 | eval $CMD2 | cat - /dev/zero > "$2" 2>/dev/null
|
|
else
|
|
ui_print "- Not block device, storing image"
|
|
eval $CMD1 | eval $CMD2 > "$2" 2>/dev/null
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
find_dtbo_image() {
|
|
DTBOIMAGE=`find_block dtbo$SLOT`
|
|
}
|
|
|
|
patch_dtbo_image() {
|
|
find_dtbo_image
|
|
if [ ! -z $DTBOIMAGE ]; then
|
|
ui_print "- DTBO image: $DTBOIMAGE"
|
|
if $MAGISKBIN/magiskboot --dtb-test $DTBOIMAGE; then
|
|
ui_print "- Backing up stock DTBO image"
|
|
$MAGISKBIN/magiskboot --compress $DTBOIMAGE $MAGISKBIN/stock_dtbo.img.gz
|
|
ui_print "- Patching DTBO to remove avb-verity"
|
|
$MAGISKBIN/magiskboot --dtb-patch $DTBOIMAGE
|
|
return 0
|
|
fi
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
sign_chromeos() {
|
|
ui_print "- Signing ChromeOS boot image"
|
|
|
|
echo > empty
|
|
./chromeos/futility vbutil_kernel --pack new-boot.img.signed \
|
|
--keyblock ./chromeos/kernel.keyblock --signprivate ./chromeos/kernel_data_key.vbprivk \
|
|
--version 1 --vmlinuz new-boot.img --config empty --arch arm --bootloader empty --flags 0x1
|
|
|
|
rm -f empty new-boot.img
|
|
mv new-boot.img.signed new-boot.img
|
|
}
|
|
|
|
remove_system_su() {
|
|
if [ -f /system/bin/su -o -f /system/xbin/su ] && [ ! -f /su/bin/su ]; then
|
|
ui_print "- Removing system installed root"
|
|
mount -o rw,remount /system
|
|
# SuperSU
|
|
if [ -e /system/bin/.ext/.su ]; then
|
|
mv -f /system/bin/app_process32_original /system/bin/app_process32 2>/dev/null
|
|
mv -f /system/bin/app_process64_original /system/bin/app_process64 2>/dev/null
|
|
mv -f /system/bin/install-recovery_original.sh /system/bin/install-recovery.sh 2>/dev/null
|
|
cd /system/bin
|
|
if [ -e app_process64 ]; then
|
|
ln -sf app_process64 app_process
|
|
elif [ -e app_process32 ]; then
|
|
ln -sf app_process32 app_process
|
|
fi
|
|
fi
|
|
rm -rf /system/.pin /system/bin/.ext /system/etc/.installed_su_daemon /system/etc/.has_su_daemon \
|
|
/system/xbin/daemonsu /system/xbin/su /system/xbin/sugote /system/xbin/sugote-mksh /system/xbin/supolicy \
|
|
/system/bin/app_process_init /system/bin/su /cache/su /system/lib/libsupol.so /system/lib64/libsupol.so \
|
|
/system/su.d /system/etc/install-recovery.sh /system/etc/init.d/99SuperSUDaemon /cache/install-recovery.sh \
|
|
/system/.supersu /cache/.supersu /data/.supersu \
|
|
/system/app/Superuser.apk /system/app/SuperSU /cache/Superuser.apk 2>/dev/null
|
|
fi
|
|
}
|
|
|
|
api_level_arch_detect() {
|
|
API=`grep_prop ro.build.version.sdk`
|
|
ABI=`grep_prop ro.product.cpu.abi | cut -c-3`
|
|
ABI2=`grep_prop ro.product.cpu.abi2 | cut -c-3`
|
|
ABILONG=`grep_prop ro.product.cpu.abi`
|
|
|
|
ARCH=arm
|
|
ARCH32=arm
|
|
IS64BIT=false
|
|
if [ "$ABI" = "x86" ]; then ARCH=x86; ARCH32=x86; fi;
|
|
if [ "$ABI2" = "x86" ]; then ARCH=x86; ARCH32=x86; fi;
|
|
if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; ARCH32=arm; IS64BIT=true; fi;
|
|
if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; ARCH32=x86; IS64BIT=true; fi;
|
|
}
|
|
|
|
check_data() {
|
|
DATA=false
|
|
DATA_DE=false
|
|
if grep ' /data ' /proc/mounts | grep -vq 'tmpfs'; then
|
|
# Test if data is writable
|
|
touch /data/.rw && rm /data/.rw && DATA=true
|
|
# Test if DE storage is writable
|
|
$DATA && [ -d /data/adb ] && touch /data/adb/.rw && rm /data/adb/.rw && DATA_DE=true
|
|
fi
|
|
$DATA && NVBASE=/data || NVBASE=/cache/data_adb
|
|
$DATA_DE && NVBASE=/data/adb
|
|
resolve_vars
|
|
}
|
|
|
|
find_manager_apk() {
|
|
APK=/data/adb/magisk.apk
|
|
[ -f $APK ] || APK=/data/magisk/magisk.apk
|
|
[ -f $APK ] || APK=/data/app/com.topjohnwu.magisk*/*.apk
|
|
if [ ! -f $APK ]; then
|
|
DBAPK=`magisk --sqlite "SELECT value FROM strings WHERE key='requester'" | cut -d= -f2`
|
|
[ -z "$DBAPK" ] || APK=/data/app/$DBAPK*/*.apk
|
|
fi
|
|
}
|
|
|
|
#################
|
|
# Module Related
|
|
#################
|
|
|
|
set_perm() {
|
|
chown $2:$3 $1 || return 1
|
|
chmod $4 $1 || return 1
|
|
CON=$5
|
|
[ -z $CON ] && CON=u:object_r:system_file:s0
|
|
chcon $CON $1 || return 1
|
|
}
|
|
|
|
set_perm_recursive() {
|
|
find $1 -type d 2>/dev/null | while read dir; do
|
|
set_perm $dir $2 $3 $4 $6
|
|
done
|
|
find $1 -type f -o -type l 2>/dev/null | while read file; do
|
|
set_perm $file $2 $3 $5 $6
|
|
done
|
|
}
|
|
|
|
mktouch() {
|
|
mkdir -p ${1%/*} 2>/dev/null
|
|
[ -z $2 ] && touch $1 || echo $2 > $1
|
|
chmod 644 $1
|
|
}
|
|
|
|
request_size_check() {
|
|
reqSizeM=`du -ms "$1" | cut -f1`
|
|
}
|
|
|
|
request_zip_size_check() {
|
|
reqSizeM=`unzip -l "$1" | tail -n 1 | awk '{ print int(($1 - 1) / 1048576 + 1) }'`
|
|
}
|
|
|
|
##################################
|
|
# Backwards Compatibile Functions
|
|
##################################
|
|
|
|
get_outfd() { setup_flashable; }
|
|
|
|
mount_magisk_img() {
|
|
$BOOTMODE && MODULE_BASE=modules_update || MODULE_BASE=modules
|
|
MODULEPATH=$NVBASE/$MODULE_BASE
|
|
mkdir -p $MODULEPATH 2>/dev/null
|
|
ln -s $MODULEPATH $MOUNTPATH
|
|
}
|
|
|
|
unmount_magisk_img() {
|
|
rm -f $MOUNTPATH 2>/dev/null
|
|
}
|
|
|
|
boot_actions() { return; }
|
|
|
|
########
|
|
# Setup
|
|
########
|
|
|
|
resolve_vars
|