Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-15 18:08:00 +01:00
parent d327c31227
commit 0b2aca0925
638 changed files with 76461 additions and 0 deletions

168
scripts/addon.d.sh Normal file
View file

@ -0,0 +1,168 @@
#!/sbin/sh
# ADDOND_VERSION=2
########################################################
#
# Magisk Survival Script for ROMs with addon.d support
# by topjohnwu and osm0sis
#
########################################################
trampoline() {
mount /data 2>/dev/null
if [ -f $MAGISKBIN/addon.d.sh ]; then
exec sh $MAGISKBIN/addon.d.sh "$@"
exit $?
elif [ "$1" = post-restore ]; then
BOOTMODE=false
ps | grep zygote | grep -v grep >/dev/null && BOOTMODE=true
$BOOTMODE || ps -A 2>/dev/null | grep zygote | grep -v grep >/dev/null && BOOTMODE=true
if ! $BOOTMODE; then
# update-binary|updater <RECOVERY_API_VERSION> <OUTFD> <ZIPFILE>
OUTFD=$(ps | grep -v 'grep' | grep -oE 'update(.*) 3 [0-9]+' | cut -d" " -f3)
[ -z $OUTFD ] && OUTFD=$(ps -Af | grep -v 'grep' | grep -oE 'update(.*) 3 [0-9]+' | cut -d" " -f3)
# update_engine_sideload --payload=file://<ZIPFILE> --offset=<OFFSET> --headers=<HEADERS> --status_fd=<OUTFD>
[ -z $OUTFD ] && OUTFD=$(ps | grep -v 'grep' | grep -oE 'status_fd=[0-9]+' | cut -d= -f2)
[ -z $OUTFD ] && OUTFD=$(ps -Af | grep -v 'grep' | grep -oE 'status_fd=[0-9]+' | cut -d= -f2)
fi
ui_print() {
if $BOOTMODE; then
log -t Magisk -- "$1"
else
echo -e "ui_print $1\nui_print" >> /proc/self/fd/$OUTFD
fi
}
ui_print "***********************"
ui_print " Magisk addon.d failed"
ui_print "***********************"
ui_print "! Cannot find Magisk binaries - was data wiped or not decrypted?"
ui_print "! Reflash OTA from decrypted recovery or reflash Magisk"
fi
exit 1
}
# Always use the script in /data
MAGISKBIN=/data/adb/magisk
[ "$0" = $MAGISKBIN/addon.d.sh ] || trampoline "$@"
V1_FUNCS=/tmp/backuptool.functions
V2_FUNCS=/postinstall/tmp/backuptool.functions
if [ -f $V1_FUNCS ]; then
. $V1_FUNCS
backuptool_ab=false
elif [ -f $V2_FUNCS ]; then
. $V2_FUNCS
else
return 1
fi
initialize() {
# Load utility functions
. $MAGISKBIN/util_functions.sh
if $BOOTMODE; then
# Override ui_print when booted
ui_print() { log -t Magisk -- "$1"; }
fi
OUTFD=
setup_flashable
}
main() {
if ! $backuptool_ab; then
# Restore PREINITDEVICE from previous A-only partition
if [ -f config.orig ]; then
PREINITDEVICE=$(grep_prop PREINITDEVICE config.orig)
rm config.orig
fi
# Wait for post addon.d-v1 processes to finish
sleep 5
fi
# Ensure we aren't in /tmp/addon.d anymore (since it's been deleted by addon.d)
mkdir -p $TMPDIR
cd $TMPDIR
if echo $MAGISK_VER | grep -q '\.'; then
PRETTY_VER=$MAGISK_VER
else
PRETTY_VER="$MAGISK_VER($MAGISK_VER_CODE)"
fi
print_title "Magisk $PRETTY_VER addon.d"
mount_partitions
check_data
get_flags
if $backuptool_ab; then
# Swap the slot for addon.d-v2
if [ ! -z $SLOT ]; then
case $SLOT in
_a) SLOT=_b;;
_b) SLOT=_a;;
esac
fi
fi
find_boot_image
[ -z $BOOTIMAGE ] && abort "! Unable to detect target image"
ui_print "- Target image: $BOOTIMAGE"
api_level_arch_detect
ui_print "- Device platform: $ABI"
remove_system_su
install_magisk
# Cleanups
cd /
$BOOTMODE || recovery_cleanup
rm -rf $TMPDIR
ui_print "- Done"
exit 0
}
case "$1" in
backup)
# Stub
;;
restore)
# Stub
;;
pre-backup)
# Back up PREINITDEVICE from existing partition before OTA on A-only devices
if ! $backuptool_ab; then
initialize
RECOVERYMODE=false
find_boot_image
$MAGISKBIN/magiskboot unpack "$BOOTIMAGE"
$MAGISKBIN/magiskboot cpio ramdisk.cpio "extract .backup/.magisk config.orig"
$MAGISKBIN/magiskboot cleanup
fi
;;
post-backup)
# Stub
;;
pre-restore)
# Stub
;;
post-restore)
initialize
if $backuptool_ab; then
su=sh
$BOOTMODE && su=su
exec $su -c "sh $0 addond-v2"
else
# Run in background, hack for addon.d-v1
(main) &
fi
;;
addond-v2)
initialize
main
;;
esac

250
scripts/app_functions.sh Normal file
View file

@ -0,0 +1,250 @@
##################################
# Magisk app internal scripts
##################################
# $1 = delay
# $2 = command
run_delay() {
(sleep $1; $2)&
}
# $1 = version string
# $2 = version code
env_check() {
for file in busybox magiskboot magiskinit util_functions.sh boot_patch.sh; do
[ -f "$MAGISKBIN/$file" ] || return 1
done
if [ "$2" -ge 25000 ]; then
[ -f "$MAGISKBIN/magiskpolicy" ] || return 1
fi
if [ "$2" -ge 25210 ]; then
[ -b "$MAGISKTMP/.magisk/device/preinit" ] || [ -b "$MAGISKTMP/.magisk/block/preinit" ] || return 2
fi
grep -xqF "MAGISK_VER='$1'" "$MAGISKBIN/util_functions.sh" || return 3
grep -xqF "MAGISK_VER_CODE=$2" "$MAGISKBIN/util_functions.sh" || return 3
return 0
}
# $1 = dir to copy
# $2 = destination (optional)
cp_readlink() {
if [ -z $2 ]; then
cd $1
else
cp -af $1/. $2
cd $2
fi
for file in *; do
if [ -L $file ]; then
local full=$(readlink -f $file)
rm $file
cp -af $full $file
fi
done
chmod -R 755 .
cd /
}
# $1 = install dir
fix_env() {
# Cleanup and make dirs
rm -rf $MAGISKBIN/*
mkdir -p $MAGISKBIN 2>/dev/null
chmod 700 /data/adb
cp_readlink $1 $MAGISKBIN
rm -rf $1
chown -R 0:0 $MAGISKBIN
}
# $1 = install dir
# $2 = boot partition
direct_install() {
echo "- Flashing new boot image"
flash_image $1/new-boot.img $2
case $? in
1)
echo "! Insufficient partition size"
return 1
;;
2)
echo "! $2 is read only"
return 2
;;
esac
rm -f $1/new-boot.img
fix_env $1
run_migrations
return 0
}
# $1 = uninstaller zip
run_uninstaller() {
rm -rf /dev/tmp
mkdir -p /dev/tmp/install
unzip -o "$1" "assets/*" "lib/*" -d /dev/tmp/install
INSTALLER=/dev/tmp/install sh /dev/tmp/install/assets/uninstaller.sh dummy 1 "$1"
}
# $1 = boot partition
restore_imgs() {
local SHA1=$(grep_prop SHA1 $MAGISKTMP/.magisk/config)
local BACKUPDIR=/data/magisk_backup_$SHA1
[ -d $BACKUPDIR ] || return 1
[ -f $BACKUPDIR/boot.img.gz ] || return 1
flash_image $BACKUPDIR/boot.img.gz $1
}
# $1 = path to bootctl executable
post_ota() {
cd /data/adb
cp -f $1 bootctl
rm -f $1
chmod 755 bootctl
if ! ./bootctl hal-info; then
rm -f bootctl
return
fi
SLOT_NUM=0
[ $(./bootctl get-current-slot) -eq 0 ] && SLOT_NUM=1
./bootctl set-active-boot-slot $SLOT_NUM
cat << EOF > post-fs-data.d/post_ota.sh
/data/adb/bootctl mark-boot-successful
rm -f /data/adb/bootctl
rm -f /data/adb/post-fs-data.d/post_ota.sh
EOF
chmod 755 post-fs-data.d/post_ota.sh
cd /
}
# $1 = APK
# $2 = package name
adb_pm_install() {
local tmp=/data/local/tmp/temp.apk
cp -f "$1" $tmp
chmod 644 $tmp
su 2000 -c pm install -g $tmp || pm install -g $tmp || su 1000 -c pm install -g $tmp
local res=$?
rm -f $tmp
if [ $res = 0 ]; then
appops set "$2" REQUEST_INSTALL_PACKAGES allow
fi
return $res
}
check_boot_ramdisk() {
# Create boolean ISAB
ISAB=true
[ -z $SLOT ] && ISAB=false
# If we are A/B, then we must have ramdisk
$ISAB && return 0
# If we are using legacy SAR, but not A/B, assume we do not have ramdisk
if $LEGACYSAR; then
# Override recovery mode to true
RECOVERYMODE=true
return 1
fi
return 0
}
check_encryption() {
if $ISENCRYPTED; then
if [ $SDK_INT -lt 24 ]; then
CRYPTOTYPE="block"
else
# First see what the system tells us
CRYPTOTYPE=$(getprop ro.crypto.type)
if [ -z $CRYPTOTYPE ]; then
# If not mounting through device mapper, we are FBE
if grep ' /data ' /proc/mounts | grep -qv 'dm-'; then
CRYPTOTYPE="file"
else
# We are either FDE or metadata encryption (which is also FBE)
CRYPTOTYPE="block"
grep -q ' /metadata ' /proc/mounts && CRYPTOTYPE="file"
fi
fi
fi
else
CRYPTOTYPE="N/A"
fi
}
printvar() {
eval echo $1=\$$1
}
run_action() {
local MODID="$1"
cd "/data/adb/modules/$MODID"
sh ./action.sh
local RES=$?
cd /
return $RES
}
##########################
# Non-root util_functions
##########################
mount_partitions() {
[ "$(getprop ro.build.ab_update)" = "true" ] && SLOT=$(getprop ro.boot.slot_suffix)
# Check whether non rootfs root dir exists
SYSTEM_AS_ROOT=false
grep ' / ' /proc/mounts | grep -qv 'rootfs' && SYSTEM_AS_ROOT=true
LEGACYSAR=false
grep ' / ' /proc/mounts | grep -q '/dev/root' && LEGACYSAR=true
}
get_flags() {
KEEPVERITY=$SYSTEM_AS_ROOT
ISENCRYPTED=false
[ "$(getprop ro.crypto.state)" = "encrypted" ] && ISENCRYPTED=true
KEEPFORCEENCRYPT=$ISENCRYPTED
if [ -n "$(getprop ro.boot.vbmeta.device)" -o -n "$(getprop ro.boot.vbmeta.size)" ]; then
PATCHVBMETAFLAG=false
elif getprop ro.product.ab_ota_partitions | grep -wq vbmeta; then
PATCHVBMETAFLAG=false
else
PATCHVBMETAFLAG=true
fi
[ -z $RECOVERYMODE ] && RECOVERYMODE=false
[ -z $VENDORBOOT ] && VENDORBOOT=false
}
run_migrations() { return; }
grep_prop() { return; }
#############
# Initialize
#############
app_init() {
mount_partitions >/dev/null
RAMDISKEXIST=false
check_boot_ramdisk && RAMDISKEXIST=true
get_flags >/dev/null
run_migrations >/dev/null
check_encryption
# Dump variables
printvar SLOT
printvar SYSTEM_AS_ROOT
printvar RAMDISKEXIST
printvar ISAB
printvar CRYPTOTYPE
printvar PATCHVBMETAFLAG
printvar LEGACYSAR
printvar RECOVERYMODE
printvar KEEPVERITY
printvar KEEPFORCEENCRYPT
printvar VENDORBOOT
}
export BOOTMODE=true

260
scripts/avd.sh Executable file
View file

@ -0,0 +1,260 @@
#!/usr/bin/env bash
set -e
shopt -s extglob
. scripts/test_common.sh
emu_args_base="-no-window -no-audio -no-boot-anim -gpu swiftshader_indirect -read-only -no-snapshot -cores $core_count"
log_args="-show-kernel -logcat '' -logcat-output logcat.log"
emu_args=
emu_pid=
atd_min_api=30
atd_max_api=36
huge_ram_min_api=26
case $(uname -m) in
'arm64'|'aarch64')
if [ -n "$FORCE_32_BIT" ]; then
echo "! ARM32 is not supported"
exit 1
fi
arch=arm64-v8a
;;
*)
if [ -n "$FORCE_32_BIT" ]; then
arch=x86
else
arch=x86_64
fi
;;
esac
cleanup() {
pkill -INT -P $$
wait
trap - EXIT
rm -f magisk_*.img
"$avd" delete avd -n test
exit 1
}
test_error() {
print_error "! An error occurred"
cleanup
}
wait_for_boot() {
set -e
adb wait-for-device
while true; do
local result="$(adb exec-out getprop sys.boot_completed)"
if [ $? -ne 0 ]; then
exit 1
elif [ "$result" = "1" ]; then
break
fi
sleep 2
done
}
wait_emu() {
local which_pid
timeout $boot_timeout bash -c wait_for_boot &
local wait_pid=$!
# Handle the case when emulator dies earlier than timeout
wait -p which_pid -n $emu_pid $wait_pid
[ $which_pid -eq $wait_pid ]
}
dump_vars() {
local val
for name in $@; do
eval val=\$$name
echo $name=\"$val\"\;
done
}
resolve_vars() {
local arg_list="$1"
local ver=$2
local type=$3
# Determine API level
local api
case $ver in
+([0-9\.])) api=$ver ;;
TiramisuPrivacySandbox) api=33 ;;
UpsideDownCakePrivacySandbox) api=34 ;;
VanillaIceCream) api=35 ;;
Baklava) api=36 ;;
*CANARY) api=10000 ;;
*)
print_error "! Unknown system image version '$ver'"
exit 1
;;
esac
# Determine default image type
if [ -z $type ]; then
if [ $(bc <<< "$api >= $atd_min_api && $api <= $atd_max_api") = 1 ]; then
# Use the lightweight ATD images if possible
type='aosp_atd'
elif [ $(bc <<< "$api > $atd_max_api") = 1 ]; then
# Preview/beta release, no AOSP version available
type='google_apis'
else
type='default'
fi
fi
# Old Linux kernels will not boot with memory larger than 3GB
local memory
if [ $(bc <<< "$api < $huge_ram_min_api") = 1 ]; then
memory=3072
else
memory=8192
fi
emu_args="$emu_args_base -memory $memory"
# System image variable and paths
local avd_pkg="system-images;android-$ver;$type;$arch"
local sys_img_dir="$ANDROID_HOME/system-images/android-$ver/$type/$arch"
local ramdisk="$sys_img_dir/ramdisk.img"
# Dump variables to output
dump_vars $arg_list
}
dl_emu() {
local avd_pkg=$1
yes | "$sdk" --licenses > /dev/null 2>&1
"$sdk" --channel=3 platform-tools emulator $avd_pkg
}
setup_emu() {
local avd_pkg=$1
dl_emu $avd_pkg
echo no | "$avd" create avd -f -n test -k $avd_pkg
}
test_emu() {
local variant=$1
local magisk_args="-ramdisk magisk_${variant}.img -feature -SystemAsRoot"
if [ -n "$AVD_TEST_LOG" ]; then
rm -f logcat.log
"$emu" @test $emu_args $log_args $magisk_args > kernel.log 2>&1 &
else
"$emu" @test $emu_args $magisk_args > /dev/null 2>&1 &
fi
emu_pid=$!
wait_emu
run_setup $variant
adb reboot
wait_emu
run_tests
kill -INT $emu_pid
wait $emu_pid
}
test_main() {
local avd_pkg ramdisk vars
vars=$(resolve_vars "emu_args avd_pkg ramdisk" $1 $2)
eval $vars
# Specify an explicit port so that tests can run with other emulators running at the same time
local emu_port=5682
emu_args="$emu_args -port $emu_port"
export ANDROID_SERIAL="emulator-$emu_port"
setup_emu "$avd_pkg"
# Restart ADB daemon just in case
adb kill-server
adb start-server
# Launch stock emulator
print_title "* Launching $avd_pkg"
"$emu" @test $emu_args >/dev/null 2>&1 &
emu_pid=$!
wait_emu
# Patch images
if [ -z "$AVD_TEST_SKIP_DEBUG" ]; then
./build.py -v avd_patch "$ramdisk" magisk_debug.img
fi
if [ -z "$AVD_TEST_SKIP_RELEASE" ]; then
./build.py -vr avd_patch "$ramdisk" magisk_release.img
fi
kill -INT $emu_pid
wait $emu_pid
if [ -z "$AVD_TEST_SKIP_DEBUG" ]; then
print_title "* Testing $avd_pkg (debug)"
test_emu debug
fi
if [ -z "$AVD_TEST_SKIP_RELEASE" ]; then
print_title "* Testing $avd_pkg (release)"
test_emu release
fi
# Cleanup
rm -f magisk_*.img
"$avd" delete avd -n test
}
run_main() {
local avd_pkg vars
vars=$(resolve_vars "emu_args avd_pkg" $1 $2)
eval $vars
setup_emu "$avd_pkg"
print_title "* Launching $avd_pkg"
"$emu" @test $emu_args 2>/dev/null
}
dl_main() {
local avd_pkg vars
vars=$(resolve_vars "avd_pkg" $1 $2)
eval $vars
print_title "* Downloading $avd_pkg"
dl_emu "$avd_pkg"
}
case "$1" in
test )
shift
trap test_error EXIT
export -f wait_for_boot
set -x
test_main "$@"
;;
run )
shift
trap cleanup EXIT
run_main "$@"
;;
dl )
shift
dl_main "$@"
;;
* )
print_error "Unknown argument '$1'"
exit 1
;;
esac
# Exit normally, don't run through cleanup again
trap - EXIT

269
scripts/boot_patch.sh Normal file
View file

@ -0,0 +1,269 @@
#!/system/bin/sh
#######################################################################################
# Magisk Boot Image Patcher
#######################################################################################
#
# Usage: boot_patch.sh <bootimage>
#
# The following environment variables can configure the installation:
# KEEPVERITY, KEEPFORCEENCRYPT, PATCHVBMETAFLAG, RECOVERYMODE, LEGACYSAR
#
# This script should be placed in a directory with the following files:
#
# File name Type Description
#
# boot_patch.sh script A script to patch boot image for Magisk.
# (this file) The script will use files in its same
# directory to complete the patching process.
# util_functions.sh script A script which hosts all functions required
# for this script to work properly.
# magiskinit binary The binary to replace /init.
# magisk binary The magisk binary.
# magiskboot binary A tool to manipulate boot images.
# init-ld binary The library that will be LD_PRELOAD of /init
# stub.apk binary The stub Magisk app to embed into ramdisk.
# chromeos folder This folder includes the utility and keys to sign
# (optional) chromeos boot images. Only used for Pixel C.
#
#######################################################################################
############
# Functions
############
# Pure bash dirname implementation
getdir() {
case "$1" in
*/*)
dir=${1%/*}
if [ -z $dir ]; then
echo "/"
else
echo $dir
fi
;;
*) echo "." ;;
esac
}
#################
# Initialization
#################
if [ -z $SOURCEDMODE ]; then
# Switch to the location of the script file
cd "$(getdir "${BASH_SOURCE:-$0}")"
# Load utility functions
. ./util_functions.sh
# Check if 64-bit
api_level_arch_detect
fi
BOOTIMAGE="$1"
[ -e "$BOOTIMAGE" ] || abort "$BOOTIMAGE does not exist!"
# Dump image for MTD/NAND character device boot partitions
if [ -c "$BOOTIMAGE" ]; then
nanddump -f boot.img "$BOOTIMAGE"
BOOTNAND="$BOOTIMAGE"
BOOTIMAGE=boot.img
fi
# Flags
[ -z $KEEPVERITY ] && KEEPVERITY=false
[ -z $KEEPFORCEENCRYPT ] && KEEPFORCEENCRYPT=false
[ -z $PATCHVBMETAFLAG ] && PATCHVBMETAFLAG=false
[ -z $RECOVERYMODE ] && RECOVERYMODE=false
[ -z $LEGACYSAR ] && LEGACYSAR=false
export KEEPVERITY
export KEEPFORCEENCRYPT
export PATCHVBMETAFLAG
chmod -R 755 .
#########
# Unpack
#########
CHROMEOS=false
VENDORBOOT=false
ui_print "- Unpacking boot image"
./magiskboot unpack "$BOOTIMAGE"
case $? in
0 ) ;;
2 )
ui_print "- ChromeOS boot image detected"
CHROMEOS=true
;;
3 )
ui_print "- Vendor boot image detected"
VENDORBOOT=true
;;
* )
abort "! Unable to unpack boot image"
;;
esac
#################
# Ramdisk Checks
#################
unset RAMDISK
for path in ramdisk.cpio vendor_ramdisk/init_boot.cpio vendor_ramdisk/ramdisk.cpio; do
if [ -e $path ]; then
RAMDISK=$path
break
fi
done
ui_print "- Checking ramdisk status"
if [ -n "$RAMDISK" ]; then
./magiskboot cpio $RAMDISK test
STATUS=$?
SKIP_BACKUP=""
else
# No ramdisk found, create one from scratch
RAMDISK=ramdisk.cpio
# Could be stock A only legacy SAR, or some Android 13 GKIs
STATUS=0
SKIP_BACKUP="#"
fi
case $STATUS in
0 )
# Stock boot
ui_print "- Stock boot image detected"
SHA1=$(./magiskboot sha1 "$BOOTIMAGE" 2>/dev/null)
cat $BOOTIMAGE > stock_boot.img
cp -af $RAMDISK ramdisk.cpio.orig 2>/dev/null
;;
1 )
# Magisk patched
ui_print "- Magisk patched boot image detected"
./magiskboot cpio $RAMDISK \
"extract .backup/.magisk config.orig" \
"restore"
cp -af $RAMDISK ramdisk.cpio.orig
rm -f stock_boot.img
;;
2 )
# Unsupported
ui_print "! Boot image patched by unsupported programs"
abort "! Please restore back to stock boot image"
;;
esac
if [ -f config.orig ]; then
# Read existing configs
chmod 0644 config.orig
SHA1=$(grep_prop SHA1 config.orig)
if ! $BOOTMODE; then
# Do not inherit config if not in recovery
PREINITDEVICE=$(grep_prop PREINITDEVICE config.orig)
fi
rm config.orig
fi
##################
# Ramdisk Patches
##################
ui_print "- Patching ramdisk"
$BOOTMODE && [ -z "$PREINITDEVICE" ] && PREINITDEVICE=$(./magisk --preinit-device)
# Compress to save precious ramdisk space
./magiskboot compress=xz magisk magisk.xz
./magiskboot compress=xz stub.apk stub.xz
./magiskboot compress=xz init-ld init-ld.xz
echo "KEEPVERITY=$KEEPVERITY" > config
echo "KEEPFORCEENCRYPT=$KEEPFORCEENCRYPT" >> config
echo "RECOVERYMODE=$RECOVERYMODE" >> config
echo "VENDORBOOT=$VENDORBOOT" >> config
if [ -n "$PREINITDEVICE" ]; then
ui_print "- Pre-init storage partition: $PREINITDEVICE"
echo "PREINITDEVICE=$PREINITDEVICE" >> config
fi
[ -n "$SHA1" ] && echo "SHA1=$SHA1" >> config
./magiskboot cpio $RAMDISK \
"add 0750 init magiskinit" \
"mkdir 0750 overlay.d" \
"mkdir 0750 overlay.d/sbin" \
"add 0644 overlay.d/sbin/magisk.xz magisk.xz" \
"add 0644 overlay.d/sbin/stub.xz stub.xz" \
"add 0644 overlay.d/sbin/init-ld.xz init-ld.xz" \
"patch" \
"$SKIP_BACKUP backup ramdisk.cpio.orig" \
"mkdir 000 .backup" \
"add 000 .backup/.magisk config" \
|| abort "! Unable to patch ramdisk"
rm -f ramdisk.cpio.orig config *.xz
#################
# Binary Patches
#################
for dt in dtb kernel_dtb extra; do
if [ -f $dt ]; then
if ! ./magiskboot dtb $dt test; then
ui_print "! Boot image $dt was patched by old (unsupported) Magisk"
abort "! Please try again with *unpatched* boot image"
fi
if ./magiskboot dtb $dt patch; then
ui_print "- Patch fstab in boot image $dt"
fi
fi
done
if [ -f kernel ]; then
PATCHEDKERNEL=false
# Remove Samsung RKP
./magiskboot hexpatch kernel \
49010054011440B93FA00F71E9000054010840B93FA00F7189000054001840B91FA00F7188010054 \
A1020054011440B93FA00F7140020054010840B93FA00F71E0010054001840B91FA00F7181010054 \
&& PATCHEDKERNEL=true
# Remove Samsung defex
# Before: [mov w2, #-221] (-__NR_execve)
# After: [mov w2, #-32768]
./magiskboot hexpatch kernel 821B8012 E2FF8F12 && PATCHEDKERNEL=true
# Disable Samsung PROCA
# proca_config -> proca_magisk
./magiskboot hexpatch kernel \
70726F63615F636F6E66696700 \
70726F63615F6D616769736B00 \
&& PATCHEDKERNEL=true
# Force kernel to load rootfs for legacy SAR devices
# skip_initramfs -> want_initramfs
$LEGACYSAR && ./magiskboot hexpatch kernel \
736B69705F696E697472616D667300 \
77616E745F696E697472616D667300 \
&& PATCHEDKERNEL=true
# If the kernel doesn't need to be patched at all,
# keep raw kernel to avoid bootloops on some weird devices
$PATCHEDKERNEL || rm -f kernel
fi
#################
# Repack & Flash
#################
ui_print "- Repacking boot image"
./magiskboot repack "$BOOTIMAGE" || abort "! Unable to repack boot image"
# Sign chromeos boot
$CHROMEOS && sign_chromeos
# Restore the original boot partition path
[ -e "$BOOTNAND" ] && BOOTIMAGE="$BOOTNAND"
# Reset any error code
true

121
scripts/cuttlefish.sh Executable file
View file

@ -0,0 +1,121 @@
#!/usr/bin/env bash
set -xe
. scripts/test_common.sh
cvd_args="-daemon -enable_sandbox=false -memory_mb=8192 -report_anonymous_usage_stats=n -cpus=$core_count"
magisk_args='-init_boot_image=magisk_patched.img'
cleanup() {
print_error "! An error occurred"
run_cvd_bin stop_cvd || true
rm -f magisk_patched.img*
}
run_cvd_bin() {
local exe=$1
shift
HOME=$CF_HOME $CF_HOME/bin/$exe "$@"
}
setup_env() {
curl -LO https://github.com/topjohnwu/magisk-files/releases/download/files/cuttlefish-base_1.2.0_amd64.deb
sudo apt-get update
sudo dpkg -i ./cuttlefish-base_*_*64.deb || sudo apt-get install -f
rm cuttlefish-base_*_*64.deb
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger
sudo usermod -aG kvm,cvdnetwork,render $USER
yes | "$sdk" --licenses > /dev/null
"$sdk" --channel=3 platform-tools
adb kill-server
adb start-server
}
download_cf() {
local branch=$1
local device=$2
if [ -z $branch ]; then
branch='aosp-android-latest-release'
fi
if [ -z $device ]; then
device='aosp_cf_x86_64_only_phone'
fi
local target="${device}-userdebug"
local build_id=$(curl -sL https://ci.android.com/builds/branches/${branch}/status.json | \
jq -r ".targets[] | select(.name == \"$target\") | .last_known_good_build")
local sys_img_url="https://ci.android.com/builds/submitted/${build_id}/${target}/latest/raw/${device}-img-${build_id}.zip"
local host_pkg_url="https://ci.android.com/builds/submitted/${build_id}/${target}/latest/raw/cvd-host_package.tar.gz"
print_title "* Download $target ($build_id) images"
curl -L $sys_img_url -o aosp_cf_phone-img.zip
curl -LO $host_pkg_url
rm -rf $CF_HOME
mkdir -p $CF_HOME
tar xvf cvd-host_package.tar.gz -C $CF_HOME
unzip aosp_cf_phone-img.zip -d $CF_HOME
rm -f cvd-host_package.tar.gz aosp_cf_phone-img.zip
}
test_cf() {
local variant=$1
run_cvd_bin stop_cvd || true
print_title "* Testing $variant builds"
timeout $boot_timeout bash -c "run_cvd_bin launch_cvd $cvd_args $magisk_args -resume=false"
adb wait-for-device
run_setup $variant
adb reboot
sleep 5
run_cvd_bin stop_cvd || true
timeout $boot_timeout bash -c "run_cvd_bin launch_cvd $cvd_args $magisk_args"
adb wait-for-device
run_tests
}
test_main() {
# Launch stock cuttlefish
run_cvd_bin launch_cvd $cvd_args -resume=false
adb wait-for-device
# Patch and test debug build
./build.py -v avd_patch "$CF_HOME/init_boot.img" magisk_patched.img
test_cf debug
# Patch and test release build
./build.py -vr avd_patch "$CF_HOME/init_boot.img" magisk_patched.img
test_cf release
# Cleanup
run_cvd_bin stop_cvd || true
rm -f magisk_patched.img*
}
if [ -z $CF_HOME ]; then
print_error "! Environment variable CF_HOME is required"
exit 1
fi
case "$1" in
setup )
setup_env
;;
download )
download_cf $2 $3
;;
test )
trap cleanup EXIT
export -f run_cvd_bin
test_main
trap - EXIT
;;
* )
exit 1
;;
esac

101
scripts/flash_script.sh Normal file
View file

@ -0,0 +1,101 @@
#MAGISK
############################################
# Magisk Flash Script (updater-script)
############################################
##############
# Preparation
##############
# Default permissions
umask 022
OUTFD=$2
COMMONDIR=$INSTALLER/assets
CHROMEDIR=$INSTALLER/assets/chromeos
if [ ! -f $COMMONDIR/util_functions.sh ]; then
echo "! Unable to extract zip file!"
exit 1
fi
# Load utility functions
. $COMMONDIR/util_functions.sh
setup_flashable
############
# Detection
############
if echo $MAGISK_VER | grep -q '\.'; then
PRETTY_VER=$MAGISK_VER
else
PRETTY_VER="$MAGISK_VER($MAGISK_VER_CODE)"
fi
print_title "Magisk $PRETTY_VER Installer"
is_mounted /data || mount /data || is_mounted /cache || mount /cache
mount_partitions
check_data
get_flags
find_boot_image
[ -z $BOOTIMAGE ] && abort "! Unable to detect target image"
ui_print "- Target image: $BOOTIMAGE"
# Detect version and architecture
api_level_arch_detect
[ $API -lt 23 ] && abort "! Magisk only support Android 6.0 and above"
ui_print "- Device platform: $ABI"
BINDIR=$INSTALLER/lib/$ABI
cd $BINDIR
for file in lib*.so; do mv "$file" "${file:3:${#file}-6}"; done
cd /
cp -af $INSTALLER/lib/$ABI32/libmagisk.so $BINDIR/magisk32 2>/dev/null
# Check if system root is installed and remove
$BOOTMODE || remove_system_su
##############
# Environment
##############
ui_print "- Constructing environment"
# Copy required files
rm -rf $MAGISKBIN 2>/dev/null
mkdir -p $MAGISKBIN 2>/dev/null
cp -af $BINDIR/. $COMMONDIR/. $BBBIN $MAGISKBIN
# Remove files only used by the Magisk app
rm -f $MAGISKBIN/bootctl $MAGISKBIN/main.jar \
$MAGISKBIN/module_installer.sh $MAGISKBIN/uninstaller.sh
chmod -R 755 $MAGISKBIN
# addon.d
if [ -d /system/addon.d ]; then
ui_print "- Adding addon.d survival script"
blockdev --setrw /dev/block/mapper/system$SLOT 2>/dev/null
mount -o rw,remount /system || mount -o rw,remount /
ADDOND=/system/addon.d/99-magisk.sh
cp -af $COMMONDIR/addon.d.sh $ADDOND
chmod 755 $ADDOND
fi
##################
# Image Patching
##################
install_magisk
# Cleanups
$BOOTMODE || recovery_cleanup
rm -rf $TMPDIR
ui_print "- Done"
exit 0

101
scripts/host_patch.sh Normal file
View file

@ -0,0 +1,101 @@
#####################################################################
# AVD MagiskInit Setup
#####################################################################
#
# Support API level: 23 - 36
#
# With an emulator booted and accessible via ADB, usage:
# ./build.py avd_patch path/to/booted/avd-image/ramdisk.img
#
# The purpose of this script is to patch AVD ramdisk.img and do a
# full integration test of magiskinit under several circumstances.
# After patching ramdisk.img, close the emulator, then select
# "Cold Boot Now" in AVD Manager to force a full reboot.
#
#####################################################################
# AVD Init Configurations:
#
# rootfs w/o early mount: API 23 - 25
# rootfs with early mount: API 26 - 27
# Legacy system-as-root: API 28
# 2 stage init: API 29 - 35
#####################################################################
if [ ! -f /system/build.prop ]; then
# Running on PC
echo 'Please run `./build.py avd_patch` instead of directly executing the script!'
exit 1
fi
cd /data/local/tmp
chmod 755 busybox
if [ -z "$FIRST_STAGE" ]; then
export FIRST_STAGE=1
export ASH_STANDALONE=1
# Re-exec script with busybox
exec ./busybox sh $0 "$@"
fi
TARGET_FILE="$1"
OUTPUT_FILE="$1.magisk"
if echo "$TARGET_FILE" | grep -q 'ramdisk'; then
IS_RAMDISK=true
else
IS_RAMDISK=false
fi
# Extract files from APK
unzip -oj magisk.apk 'assets/util_functions.sh' 'assets/stub.apk'
. ./util_functions.sh
api_level_arch_detect
unzip -oj magisk.apk "lib/$ABI/*" -x "lib/$ABI/libbusybox.so"
for file in lib*.so; do
chmod 755 $file
mv "$file" "${file:3:${#file}-6}"
done
if $IS_RAMDISK; then
./magiskboot decompress "$TARGET_FILE" ramdisk.cpio
else
./magiskboot unpack "$TARGET_FILE"
fi
cp ramdisk.cpio ramdisk.cpio.orig
export KEEPVERITY=true
export KEEPFORCEENCRYPT=true
echo "KEEPVERITY=$KEEPVERITY" > config
echo "KEEPFORCEENCRYPT=$KEEPFORCEENCRYPT" >> config
echo "PREINITDEVICE=$(./magisk --preinit-device)" >> config
# For API 28, we also manually disable SystemAsRoot
# Explicitly override skip_initramfs by setting RECOVERYMODE=true
[ $API = "28" ] && echo 'RECOVERYMODE=true' >> config
cat config
./magiskboot compress=xz magisk magisk.xz
./magiskboot compress=xz stub.apk stub.xz
./magiskboot compress=xz init-ld init-ld.xz
./magiskboot cpio ramdisk.cpio \
"add 0750 init magiskinit" \
"mkdir 0750 overlay.d" \
"mkdir 0750 overlay.d/sbin" \
"add 0644 overlay.d/sbin/magisk.xz magisk.xz" \
"add 0644 overlay.d/sbin/stub.xz stub.xz" \
"add 0644 overlay.d/sbin/init-ld.xz init-ld.xz" \
"patch" \
"backup ramdisk.cpio.orig" \
"mkdir 000 .backup" \
"add 000 .backup/.magisk config"
rm -f ramdisk.cpio.orig config *.xz
if $IS_RAMDISK; then
./magiskboot compress=gzip ramdisk.cpio "$OUTPUT_FILE"
else
./magiskboot repack "$TARGET_FILE" "$OUTPUT_FILE"
./magiskboot cleanup
fi

177
scripts/live_setup.sh Executable file
View file

@ -0,0 +1,177 @@
#####################################################################
# AVD Magisk Setup
#####################################################################
#
# Support API level: 23 - 36
#
# For developing Magisk, just use:
# ./build.py emulator
#
# This script will stop zygote, simulate the Magisk start up process
# that would've happened before zygote was started, and finally
# restart zygote. This is useful for setting up the emulator for
# developing Magisk, testing modules, and developing root apps using
# the official Android emulator (AVD) instead of a real device.
#
# This only covers the "core" features of Magisk. For testing
# magiskinit, please checkout avd_patch.sh.
#
#####################################################################
mount_tmpfs() {
# If a file name 'magisk' is in current directory, mount will fail
mv magisk magisk.tmp
mount -t tmpfs -o 'mode=0755' magisk $1
mv magisk.tmp magisk
}
mount_sbin() {
mount_tmpfs /sbin
chcon u:object_r:rootfs:s0 /sbin
}
if [ ! -f /system/build.prop ]; then
# Running on PC
echo 'Please run `./build.py emulator` instead of directly executing the script!'
exit 1
fi
cd /data/local/tmp
chmod 755 busybox
if [ -z "$FIRST_STAGE" ]; then
export FIRST_STAGE=1
export ASH_STANDALONE=1
if [ $(./busybox id -u) -ne 0 ]; then
# Re-exec script with root
exec /system/xbin/su 0 /data/local/tmp/busybox sh $0
else
# Re-exec script with busybox
exec ./busybox sh $0
fi
fi
pm install -r -g $(pwd)/magisk.apk
# Extract files from APK
unzip -oj magisk.apk 'assets/util_functions.sh' 'assets/stub.apk'
. ./util_functions.sh
api_level_arch_detect
unzip -oj magisk.apk "lib/$ABI/*" -x "lib/$ABI/libbusybox.so"
for file in lib*.so; do
chmod 755 $file
mv "$file" "${file:3:${#file}-6}"
done
if $IS64BIT && [ -e "/system/bin/linker" ]; then
unzip -oj magisk.apk "lib/$ABI32/libmagisk.so"
mv libmagisk.so magisk32
chmod 755 magisk32
fi
# Stop zygote (and previous setup if exists)
magisk --stop 2>/dev/null
stop
if [ -d /debug_ramdisk ]; then
umount -l /debug_ramdisk 2>/dev/null
fi
# Make sure boot completed props are not set to 1
setprop sys.boot_completed 0
# Mount /cache if not already mounted
if ! grep -q ' /cache ' /proc/mounts; then
mount -t tmpfs -o 'mode=0755' tmpfs /cache
fi
MAGISKTMP=/sbin
# Setup bin overlay
if mount | grep -q rootfs; then
# Legacy rootfs
mount -o rw,remount /
rm -rf /root
mkdir /root /sbin 2>/dev/null
chmod 750 /root /sbin
ln /sbin/* /root
mount -o ro,remount /
mount_sbin
ln -s /root/* /sbin
elif [ -e /sbin ]; then
# Legacy SAR
mount_sbin
mkdir -p /dev/sysroot
block=$(mount | grep ' / ' | awk '{ print $1 }')
[ $block = "/dev/root" ] && block=/dev/block/vda1
mount -o ro $block /dev/sysroot
for file in /dev/sysroot/sbin/*; do
[ ! -e $file ] && break
if [ -L $file ]; then
cp -af $file /sbin
else
sfile=/sbin/$(basename $file)
touch $sfile
mount -o bind $file $sfile
fi
done
umount -l /dev/sysroot
rm -rf /dev/sysroot
else
# Android Q+ without sbin
MAGISKTMP=/debug_ramdisk
mount_tmpfs /debug_ramdisk
fi
# Magisk stuff
mkdir -p $MAGISKBIN 2>/dev/null
unzip -oj magisk.apk 'assets/*.sh' -d $MAGISKBIN
mkdir /data/adb/modules 2>/dev/null
mkdir /data/adb/post-fs-data.d 2>/dev/null
mkdir /data/adb/service.d 2>/dev/null
for file in magisk magisk32 magiskpolicy stub.apk; do
chmod 755 ./$file
cp -af ./$file $MAGISKTMP/$file
cp -af ./$file $MAGISKBIN/$file
done
cp -af ./magiskboot $MAGISKBIN/magiskboot
cp -af ./magiskinit $MAGISKBIN/magiskinit
cp -af ./busybox $MAGISKBIN/busybox
ln -s ./magisk $MAGISKTMP/su
ln -s ./magisk $MAGISKTMP/resetprop
ln -s ./magiskpolicy $MAGISKTMP/supolicy
mkdir -p $MAGISKTMP/.magisk/device
mkdir -p $MAGISKTMP/.magisk/worker
mount_tmpfs $MAGISKTMP/.magisk/worker
mount --make-private $MAGISKTMP/.magisk/worker
touch $MAGISKTMP/.magisk/config
export MAGISKTMP
MAKEDEV=1 $MAGISKTMP/magisk --preinit-device 2>&1
RULESCMD=""
rule="$MAGISKTMP/.magisk/preinit/sepolicy.rule"
[ -f "$rule" ] && RULESCMD="--apply $rule"
# SELinux stuffs
if [ -d /sys/fs/selinux ]; then
if [ -f /vendor/etc/selinux/precompiled_sepolicy ]; then
./magiskpolicy --load /vendor/etc/selinux/precompiled_sepolicy --live --magisk $RULESCMD 2>&1
elif [ -f /sepolicy ]; then
./magiskpolicy --load /sepolicy --live --magisk $RULESCMD 2>&1
else
./magiskpolicy --live --magisk $RULESCMD 2>&1
fi
fi
# Boot up
$MAGISKTMP/magisk --post-fs-data
start
$MAGISKTMP/magisk --service
# Make sure reset nb prop after zygote starts
sleep 2
$MAGISKTMP/magisk --boot-complete

View file

@ -0,0 +1,33 @@
#!/sbin/sh
#################
# Initialization
#################
umask 022
# echo before loading util_functions
ui_print() { echo "$1"; }
require_new_magisk() {
ui_print "*******************************"
ui_print " Please install Magisk v20.4+! "
ui_print "*******************************"
exit 1
}
#########################
# Load util_functions.sh
#########################
OUTFD=$2
ZIPFILE=$3
mount /data 2>/dev/null
[ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk
. /data/adb/magisk/util_functions.sh
[ $MAGISK_VER_CODE -lt 20400 ] && require_new_magisk
install_module
exit 0

173
scripts/release.sh Executable file
View file

@ -0,0 +1,173 @@
#!/usr/bin/env bash
set -e
# On macOS, gsed is required (brew install gnu-sed)
# Required tools: gh
# The GitHub cli (gh) has to be properly authenticated
# These variables can be modified as needed
CONFIG=config.prop
NOTES=notes.md
# These are constants, do not modify
GCONFIG=app/gradle.properties
BUILDCMD="./build.py -c $CONFIG"
CWD=$(pwd)
grep_prop() {
local REGEX="s/^$1=//p"
shift
local FILES=$@
sed -n "$REGEX" $FILES | head -n 1
}
ensure_config() {
# Make sure version is not commented out and exists
sed -i "s:^# version=:version=:g" $CONFIG
if ! grep -qE '^version=' $CONFIG; then
echo 'version=' >> $CONFIG
fi
# Make sure abiList is not set when building for release
sed -i "s:^abiList=:# abiList=:g" $CONFIG
}
disable_version_config() {
# Comment out version config
sed -i "s:^version=:# version=:g" $CONFIG
}
bump_canary_version() {
# Update version code
local code=$(grep_prop magisk.versionCode $GCONFIG)
code=$((code + 1))
local tag="canary-$code"
sed -i "s:versionCode=.*:versionCode=${code}:g" $GCONFIG
# Commit version code changes
git add -u .
git status
git commit -m "Release new canary build" -m "[skip ci]"
git tag $tag
# Update version name
local ver=$(git rev-parse --short=8 HEAD)
sed -i "s:version=.*:version=${ver}:g" $CONFIG
sed -i "1s:.*:## Magisk (${ver}) (${code}):" $NOTES
}
# $1 = ver
set_version() {
local ver=$1
local code=$(echo - | awk "{ print $ver * 1000 }")
local tag="v$ver"
sed -i "s:versionCode=.*:versionCode=${code}:g" $GCONFIG
sed -i "s:version=.*:version=${ver}:g" $CONFIG
sed -i "1s:.*:## $(date +'%Y.%-m.%-d') Magisk v$ver:" $NOTES
# Commit version code changes
git add -u .
git status
git commit -m "Release Magisk v$ver" -m "[skip ci]"
git tag $tag
}
build_apk() {
$BUILDCMD clean
$BUILDCMD all
$BUILDCMD -r all
}
build_canary() {
bump_canary_version
build_apk
}
# $1 = ver
build_public() {
[ -z $1 ] && exit 1
local ver=$1
set_version $ver
build_apk
}
upload() {
# Verify pattern
[[ "$1" =~ canary|beta|stable ]]
local type=$1
gh auth status
local latest_tag=$(git describe --abbrev=0 --tags)
local ver=$(grep_prop version $CONFIG)
local code=$(grep_prop magisk.versionCode $GCONFIG)
local out=$(grep_prop outdir $CONFIG)
local tag title
if [ -z $out ]; then
out=out
fi
git push origin master
git push --tags
# Prepare release notes
tail -n +3 $NOTES > release.md
case $type in
canary )
tag="canary-$code"
title="Magisk ($ver) ($code)"
# Assert tag format
[ $latest_tag = $tag ]
# Publish release
gh release create --verify-tag $tag -p -t "$title" -F release.md $out/app-release.apk $out/app-debug.apk $NOTES
;;
beta|stable )
tag="v$ver"
title="Magisk v$ver"
# Assert tag format
[ $latest_tag = $tag ]
# Publish release
local release_apk="Magisk-v${ver}.apk"
cp $out/app-release.apk $release_apk
gh release create --verify-tag $tag -p -t "$title" -F release.md $release_apk $out/app-debug.apk $NOTES
rm -f $release_apk
;;
esac
# If publishing stable, make it not prerelease and explicitly latest
if [ $type = "stable" ]; then
gh release edit $tag --prerelease=false --latest
fi
rm -f release.md
}
revert() {
local latest_tag=$(git describe --abbrev=0 --tags)
git tag -d $latest_tag
git reset --hard HEAD~
}
# Use GNU sed on macOS
if command -v gsed >/dev/null; then
function sed() { gsed "$@"; }
export -f sed
fi
git pull
trap disable_version_config EXIT
ensure_config
case $1 in
canary ) build_canary ;;
public ) build_public $2 ;;
upload ) upload $2 ;;
revert ) revert ;;
* ) exit 1 ;;
esac

87
scripts/test_common.sh Normal file
View file

@ -0,0 +1,87 @@
if [ -z $ANDROID_HOME ]; then
export ANDROID_HOME=$ANDROID_SDK_ROOT
fi
# Make sure paths are consistent
export ANDROID_USER_HOME="$HOME/.android"
export ANDROID_EMULATOR_HOME="$ANDROID_USER_HOME"
export ANDROID_AVD_HOME="$ANDROID_EMULATOR_HOME/avd"
export PATH="$PATH:$ANDROID_HOME/platform-tools"
emu="$ANDROID_HOME/emulator/emulator"
sdk="$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager"
avd="$ANDROID_HOME/cmdline-tools/latest/bin/avdmanager"
boot_timeout=100
core_count=$(nproc)
if [ $core_count -gt 8 ]; then
core_count=8
fi
print_title() {
echo -e "\n\033[44;39m${1}\033[0m\n"
}
print_error() {
echo -e "\n\033[41;39m${1}\033[0m\n" >&2
}
# $1 = TestClass#method
# $2 = component
am_instrument() {
set +x
local out=$(adb shell am instrument -w --user 0 -e class "$1" "$2")
echo "$out"
if grep -q 'OK (' <<< "$out"; then
set -x
return 0
else
set -x
return 1
fi
}
# $1 = pkg
wait_for_pm() {
sleep 5
adb shell pm uninstall $1 || true
}
run_setup() {
local variant=$1
adb shell 'PATH=$PATH:/debug_ramdisk magisk -v'
# Install the Magisk app
adb install -r -g out/app-${variant}.apk
# Install the test app
adb install -r -g out/test.apk
local app='com.topjohnwu.magisk.test/com.topjohnwu.magisk.test.AppTestRunner'
# Run setup through the test app
am_instrument '.Environment#setupEnvironment' $app
}
run_tests() {
local pkg='com.topjohnwu.magisk.test'
local self="$pkg/$pkg.TestRunner"
local app="$pkg/$pkg.AppTestRunner"
local stub="repackaged.$pkg/$pkg.AppTestRunner"
# Run app tests
am_instrument '.MagiskAppTest,.AdditionalTest' $app
# Test app hiding
am_instrument '.AppMigrationTest#testAppHide' $self
# Make sure it still works
am_instrument '.MagiskAppTest' $stub
# Test app restore
am_instrument '.AppMigrationTest#testAppRestore' $self
# Make sure it still works
am_instrument '.MagiskAppTest' $app
}

181
scripts/uninstaller.sh Normal file
View file

@ -0,0 +1,181 @@
#MAGISK
############################################
# Magisk Uninstaller (updater-script)
############################################
##############
# Preparation
##############
# Default permissions
umask 022
OUTFD=$2
COMMONDIR=$INSTALLER/assets
CHROMEDIR=$INSTALLER/assets/chromeos
if [ ! -f $COMMONDIR/util_functions.sh ]; then
echo "! Unable to extract zip file!"
exit 1
fi
# Load utility functions
. $COMMONDIR/util_functions.sh
setup_flashable
############
# Detection
############
if echo $MAGISK_VER | grep -q '\.'; then
PRETTY_VER=$MAGISK_VER
else
PRETTY_VER="$MAGISK_VER($MAGISK_VER_CODE)"
fi
print_title "Magisk $PRETTY_VER Uninstaller"
is_mounted /data || mount /data || abort "! Unable to mount /data, please uninstall with the Magisk app"
mount_partitions
check_data
$DATA_DE || abort "! Cannot access /data, please uninstall with the Magisk app"
get_flags
find_boot_image
[ -z $BOOTIMAGE ] && abort "! Unable to detect target image"
ui_print "- Target image: $BOOTIMAGE"
# Detect version and architecture
api_level_arch_detect
ui_print "- Device platform: $ABI"
BINDIR=$INSTALLER/lib/$ABI
cd $BINDIR
for file in lib*.so; do mv "$file" "${file:3:${#file}-6}"; done
cd /
cp -af $CHROMEDIR/. $BINDIR/chromeos
chmod -R 755 $BINDIR
############
# Uninstall
############
cd $BINDIR
CHROMEOS=false
ui_print "- Unpacking boot image"
# Dump image for MTD/NAND character device boot partitions
if [ -c $BOOTIMAGE ]; then
nanddump -f boot.img $BOOTIMAGE
BOOTNAND=$BOOTIMAGE
BOOTIMAGE=boot.img
fi
./magiskboot unpack "$BOOTIMAGE"
case $? in
1 )
abort "! Unsupported/Unknown image format"
;;
2 )
ui_print "- ChromeOS boot image detected"
CHROMEOS=true
;;
esac
# Restore the original boot partition path
[ "$BOOTNAND" ] && BOOTIMAGE=$BOOTNAND
# Detect boot image state
ui_print "- Checking ramdisk status"
if [ -e ramdisk.cpio ]; then
./magiskboot cpio ramdisk.cpio test
STATUS=$?
else
# Stock A only system-as-root
STATUS=0
fi
case $((STATUS & 3)) in
0 ) # Stock boot
ui_print "- Stock boot image detected"
;;
1 ) # Magisk patched
ui_print "- Magisk patched image detected"
# Find SHA1 of stock boot image
./magiskboot cpio ramdisk.cpio "extract .backup/.magisk config.orig"
if [ -f config.orig ]; then
chmod 0644 config.orig
SHA1=$(grep_prop SHA1 config.orig)
rm config.orig
fi
BACKUPDIR=/data/magisk_backup_$SHA1
if [ -d $BACKUPDIR ]; then
ui_print "- Restoring stock boot image"
flash_image $BACKUPDIR/boot.img.gz $BOOTIMAGE
for name in dtb dtbo dtbs; do
[ -f $BACKUPDIR/${name}.img.gz ] || continue
IMAGE=$(find_block $name$SLOT)
[ -z $IMAGE ] && continue
ui_print "- Restoring stock $name image"
flash_image $BACKUPDIR/${name}.img.gz $IMAGE
done
else
ui_print "! Boot image backup unavailable"
ui_print "- Restoring ramdisk with internal backup"
./magiskboot cpio ramdisk.cpio restore
if ! ./magiskboot cpio ramdisk.cpio "exists init"; then
# A only system-as-root
rm -f ramdisk.cpio
fi
./magiskboot repack $BOOTIMAGE
# Sign chromeos boot
$CHROMEOS && sign_chromeos
ui_print "- Flashing restored boot image"
flash_image new-boot.img $BOOTIMAGE || abort "! Insufficient partition size"
fi
;;
2 ) # Unsupported
ui_print "! Boot image patched by unsupported programs"
abort "! Cannot uninstall"
;;
esac
if $BOOTMODE; then
ui_print "- Removing modules"
magisk --remove-modules -n
fi
ui_print "- Removing Magisk files"
rm -rf \
/cache/*magisk* /cache/unblock /data/*magisk* /data/cache/*magisk* /data/property/*magisk* \
/data/Magisk.apk /data/busybox /data/custom_ramdisk_patch.sh /data/adb/*magisk* \
/data/adb/post-fs-data.d /data/adb/service.d /data/adb/modules* \
/data/unencrypted/magisk /metadata/magisk /metadata/watchdog/magisk /persist/magisk /mnt/vendor/persist/magisk
ADDOND=/system/addon.d/99-magisk.sh
if [ -f $ADDOND ]; then
blockdev --setrw /dev/block/mapper/system$SLOT 2>/dev/null
mount -o rw,remount /system || mount -o rw,remount /
rm -f $ADDOND
fi
cd /
if $BOOTMODE; then
ui_print "********************************************"
ui_print " The Magisk app will uninstall itself, and"
ui_print " the device will reboot after a few seconds"
ui_print "********************************************"
(sleep 8; /system/bin/reboot)&
else
ui_print "********************************************"
ui_print " The Magisk app will not be uninstalled"
ui_print " Please uninstall it manually after reboot"
ui_print "********************************************"
recovery_cleanup
ui_print "- Done"
fi
rm -rf $TMPDIR
exit 0

27
scripts/update_binary.sh Normal file
View file

@ -0,0 +1,27 @@
#!/sbin/sh
TMPDIR=/dev/tmp
rm -rf $TMPDIR
mkdir -p $TMPDIR 2>/dev/null
export BBBIN=$TMPDIR/busybox
for arch in "x86_64" "x86" "arm64-v8a" "armeabi-v7a"; do
unzip -o "$3" "lib/$arch/libbusybox.so" -d $TMPDIR >&2
libpath="$TMPDIR/lib/$arch/libbusybox.so"
chmod 755 $libpath
if [ -x $libpath ] && $libpath >/dev/null 2>&1; then
mv -f $libpath $BBBIN
break
fi
done
$BBBIN rm -rf $TMPDIR/lib
export INSTALLER=$TMPDIR/install
$BBBIN mkdir -p $INSTALLER
$BBBIN unzip -o "$3" "assets/*" "lib/*" "META-INF/com/google/*" -x "lib/*/libbusybox.so" -d $INSTALLER >&2
export ASH_STANDALONE=1
if echo "$3" | $BBBIN grep -q "uninstall"; then
exec $BBBIN sh "$INSTALLER/assets/uninstaller.sh" "$@"
else
exec $BBBIN sh "$INSTALLER/META-INF/com/google/android/updater-script" "$@"
fi

763
scripts/util_functions.sh Normal file
View file

@ -0,0 +1,763 @@
############################################
# Magisk General Utility Functions
############################################
#MAGISK_VERSION_STUB
###################
# Global Variables
###################
# True if the script is running on booted Android, not something like recovery
# BOOTMODE=
# The path to store temporary files that don't need to persist
# TMPDIR=
# The non-volatile path where magisk executables are stored
# MAGISKBIN=
###################
# Helper Functions
###################
ui_print() {
if $BOOTMODE; then
echo "$1"
else
echo -e "ui_print $1\nui_print" >> /proc/self/fd/$OUTFD
fi
}
toupper() {
echo "$@" | tr '[:lower:]' '[:upper:]'
}
grep_cmdline() {
local REGEX="s/^$1=//p"
{ echo $(cat /proc/cmdline)$(sed -e 's/[^"]//g' -e 's/""//g' /proc/cmdline) | xargs -n 1; \
sed -e 's/ = /=/g' -e 's/, /,/g' -e 's/"//g' /proc/bootconfig; \
} 2>/dev/null | sed -n "$REGEX"
}
grep_prop() {
local REGEX="s/^$1=//p"
shift
local FILES=$@
[ -z "$FILES" ] && FILES='/system/build.prop'
cat $FILES 2>/dev/null | dos2unix | sed -n "$REGEX" | head -n 1
}
grep_get_prop() {
local result=$(grep_prop $@)
if [ -z "$result" ]; then
# Fallback to getprop
getprop "$1"
else
echo $result
fi
}
getvar() {
local VARNAME=$1
local VALUE
local PROPPATH='/data/.magisk /cache/.magisk'
[ ! -z $MAGISKTMP ] && PROPPATH="$MAGISKTMP/.magisk/config $PROPPATH"
VALUE=$(grep_prop $VARNAME $PROPPATH)
[ ! -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
[ ! -z $MODPATH ] && rm -rf $MODPATH
rm -rf $TMPDIR
exit 1
}
print_title() {
local len line1len line2len bar
line1len=$(echo -n $1 | wc -c)
line2len=$(echo -n $2 | wc -c)
len=$line2len
[ $line1len -gt $line2len ] && len=$line1len
len=$((len + 2))
bar=$(printf "%${len}s" | tr ' ' '*')
ui_print "$bar"
ui_print " $1 "
[ "$2" ] && ui_print " $2 "
ui_print "$bar"
}
######################
# Environment Related
######################
setup_flashable() {
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 -qE " 3 $FD |status_fd=$FD"; then
OUTFD=$FD
break
fi
fi
done
fi
recovery_actions
}
ensure_bb() {
if set -o | grep -q standalone; then
# We are definitely in busybox ash
set -o standalone
return
fi
# Find our busybox binary
local bb
if [ -f $TMPDIR/busybox ]; then
bb=$TMPDIR/busybox
elif [ -f $MAGISKBIN/busybox ]; then
bb=$MAGISKBIN/busybox
else
abort "! Cannot find BusyBox"
fi
chmod 755 $bb
# Busybox could be a script, make sure /system/bin/sh exists
if [ ! -f /system/bin/sh ]; then
umount -l /system 2>/dev/null
mkdir -p /system/bin
ln -s $(command -v sh) /system/bin/sh
fi
export ASH_STANDALONE=1
# Find our current arguments
# Run in busybox environment to ensure consistent results
# /proc/<pid>/cmdline shall be <interpreter> <script> <arguments...>
local cmds="$($bb sh -c "
for arg in \$(tr '\0' '\n' < /proc/$$/cmdline); do
if [ -z \"\$cmds\" ]; then
# Skip the first argument as we want to change the interpreter
cmds=\"sh\"
else
cmds=\"\$cmds '\$arg'\"
fi
done
echo \$cmds")"
# Re-exec our script
echo $cmds | $bb xargs $bb
exit
}
recovery_actions() {
# Make sure random won'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
}
recovery_cleanup() {
local DIR
ui_print "- Unmounting partitions"
(
if [ ! -d /postinstall/tmp ]; then
umount -l /system
umount -l /system_root
fi
umount -l /vendor
umount -l /persist
umount -l /metadata
for DIR in /apex /system /system_root; do
if [ -L "${DIR}_link" ]; then
rmdir $DIR
mv -f ${DIR}_link $DIR
fi
done
umount -l /dev/random
) 2>/dev/null
[ -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
}
#######################
# Installation Related
#######################
# find_block [partname...]
find_block() {
local BLOCK DEV DEVICE DEVNAME PARTNAME UEVENT
for BLOCK in "$@"; do
DEVICE=$(find /dev/block \( -type b -o -type c -o -type l \) -iname $BLOCK | head -n 1) 2>/dev/null
if [ ! -z $DEVICE ]; then
echo $DEVICE
return 0
fi
done
# Fallback by parsing sysfs uevents
for UEVENT in /sys/dev/block/*/uevent; do
DEVNAME=$(grep_prop DEVNAME $UEVENT)
PARTNAME=$(grep_prop PARTNAME $UEVENT)
for BLOCK in "$@"; do
if [ "$(toupper $BLOCK)" = "$(toupper $PARTNAME)" ]; then
echo /dev/block/$DEVNAME
return 0
fi
done
done
# Look just in /dev in case we're dealing with MTD/NAND without /dev/block devices/links
for DEV in "$@"; do
DEVICE=$(find /dev \( -type b -o -type c -o -type l \) -maxdepth 1 -iname $DEV | head -n 1) 2>/dev/null
if [ ! -z $DEVICE ]; then
echo $DEVICE
return 0
fi
done
return 1
}
# setup_mntpoint <mountpoint>
setup_mntpoint() {
local POINT=$1
[ -L $POINT ] && mv -f $POINT ${POINT}_link
if [ ! -d $POINT ]; then
rm -f $POINT
mkdir -p $POINT
fi
}
# mount_name <partname(s)> <mountpoint> <flag>
mount_name() {
local PART=$1
local POINT=$2
local FLAG=$3
setup_mntpoint $POINT
is_mounted $POINT && return
# First try mounting with fstab
mount $FLAG $POINT 2>/dev/null
if ! is_mounted $POINT; then
local BLOCK=$(find_block $PART)
mount $FLAG $BLOCK $POINT || return
fi
ui_print "- Mounting $POINT"
}
# mount_ro_ensure <partname(s)> <mountpoint>
mount_ro_ensure() {
# We handle ro partitions only in recovery
$BOOTMODE && return
local PART=$1
local POINT=$2
mount_name "$PART" $POINT '-o ro'
is_mounted $POINT || abort "! Cannot mount $POINT"
}
# After calling this method, the following variables will be set:
# SLOT, SYSTEM_AS_ROOT, LEGACYSAR
mount_partitions() {
# Check A/B slot
SLOT=$(grep_cmdline androidboot.slot_suffix)
if [ -z $SLOT ]; then
SLOT=$(grep_cmdline androidboot.slot)
[ -z $SLOT ] || SLOT=_${SLOT}
fi
[ "$SLOT" = "normal" ] && unset SLOT
[ -z $SLOT ] || ui_print "- Current boot slot: $SLOT"
# Mount ro partitions
if is_mounted /system_root; then
umount /system 2>/dev/null
umount /system_root 2>/dev/null
fi
mount_ro_ensure "system$SLOT app$SLOT" /system
if [ -f /system/init -o -L /system/init ]; then
SYSTEM_AS_ROOT=true
setup_mntpoint /system_root
if ! mount --move /system /system_root; then
umount /system
umount -l /system 2>/dev/null
mount_ro_ensure "system$SLOT app$SLOT" /system_root
fi
mount -o bind /system_root/system /system
else
if grep ' / ' /proc/mounts | grep -qv 'rootfs' || grep -q ' /system_root ' /proc/mounts; then
SYSTEM_AS_ROOT=true
else
SYSTEM_AS_ROOT=false
fi
fi
$SYSTEM_AS_ROOT && ui_print "- Device is system-as-root"
LEGACYSAR=false
if $BOOTMODE; then
grep ' / ' /proc/mounts | grep -q '/dev/root' && LEGACYSAR=true
else
# Recovery mode, assume devices that don't use dynamic partitions are legacy SAR
local IS_DYNAMIC=false
if grep -q 'androidboot.super_partition' /proc/cmdline; then
IS_DYNAMIC=true
elif [ -n "$(find_block super)" ]; then
IS_DYNAMIC=true
fi
if $SYSTEM_AS_ROOT && ! $IS_DYNAMIC; then
LEGACYSAR=true
ui_print "- Legacy SAR, force kernel to load rootfs"
fi
fi
}
# After calling this method, the following variables will be set:
# ISENCRYPTED, PATCHVBMETAFLAG,
# KEEPVERITY, KEEPFORCEENCRYPT, RECOVERYMODE, VENDORBOOT
get_flags() {
if grep ' /data ' /proc/mounts | grep -q 'dm-'; then
ISENCRYPTED=true
elif [ "$(getprop ro.crypto.state)" = "encrypted" ]; then
ISENCRYPTED=true
elif [ "$DATA" = "false" ]; then
# No data access means unable to decrypt in recovery
ISENCRYPTED=true
else
ISENCRYPTED=false
fi
if [ -n "$(find_block vbmeta vbmeta_a)" ]; then
PATCHVBMETAFLAG=false
else
PATCHVBMETAFLAG=true
ui_print "- No vbmeta partition, patch vbmeta in boot image"
fi
# Overridable config flags with safe defaults
getvar KEEPVERITY
getvar KEEPFORCEENCRYPT
getvar RECOVERYMODE
getvar VENDORBOOT
if [ -z $KEEPVERITY ]; then
if $SYSTEM_AS_ROOT; then
KEEPVERITY=true
ui_print "- System-as-root, keep dm-verity"
else
KEEPVERITY=false
fi
fi
if [ -z $KEEPFORCEENCRYPT ]; then
if $ISENCRYPTED; then
KEEPFORCEENCRYPT=true
ui_print "- Encrypted data, keep forceencrypt"
else
KEEPFORCEENCRYPT=false
fi
fi
[ -z $RECOVERYMODE ] && RECOVERYMODE=false
[ -z $VENDORBOOT ] && VENDORBOOT=false
}
# Returns whether the device is GKI 13+
is_gt_gki_13() {
[ "$(uname -r | cut -d. -f1)" -ge 5 ] && uname -r | grep -Evq "android12-|^5\.4"
}
# Require RECOVERYMODE, VENDORBOOT, SLOT to be set.
# After calling this method, BOOTIMAGE will be set.
find_boot_image() {
BOOTIMAGE=
if $VENDORBOOT; then
BOOTIMAGE="/dev/block/by-name/vendor_boot$SLOT"
elif $RECOVERYMODE; then
BOOTIMAGE=$(find_block "recovery$SLOT" "sos")
elif [ -e "/dev/block/by-name/init_boot$SLOT" ] && is_gt_gki_13; then
# init_boot is only used with GKI 13+. It is possible that some devices with init_boot
# partition still uses Android 12 GKI or previous kernels, so we need to explicitly detect that scenario.
BOOTIMAGE="/dev/block/by-name/init_boot$SLOT"
elif [ -e "/dev/block/by-name/boot$SLOT" ]; then
# Standard location since AOSP Android 10+
BOOTIMAGE="/dev/block/by-name/boot$SLOT"
elif [ -n "$SLOT" ]; then
# Fallback for A/B devices running < Android 10
BOOTIMAGE=$(find_block "ramdisk$SLOT" "boot$SLOT")
else
# Fallback for all legacy and non-standard devices
BOOTIMAGE=$(find_block ramdisk kern-a android_boot kernel bootimg boot lnx boot_a)
fi
if [ -z $BOOTIMAGE ]; then
# Lets see what fstabs tells me
BOOTIMAGE=$(grep -v '#' /etc/*fstab* | grep -E '/boot(img)?[^a-zA-Z]' | grep -oE '/dev/[a-zA-Z0-9_./-]*' | head -n 1)
fi
}
flash_image() {
local CMD1
case "$1" in
*.gz) CMD1="gzip -d < '$1' 2>/dev/null";;
*) CMD1="cat '$1'";;
esac
if [ -b "$2" ]; then
local img_sz=$(stat -c '%s' "$1")
local blk_sz=$(blockdev --getsize64 "$2")
[ "$img_sz" -gt "$blk_sz" ] && return 1
blockdev --setrw "$2"
local blk_ro=$(blockdev --getro "$2")
[ "$blk_ro" -eq 1 ] && return 2
eval "$CMD1" | cat - /dev/zero > "$2" 2>/dev/null
elif [ -c "$2" ]; then
flash_eraseall "$2" >&2
eval "$CMD1" | nandwrite -p "$2" - >&2
else
ui_print "- Not block or char device, storing image"
eval "$CMD1" > "$2" 2>/dev/null
fi
return 0
}
# Common installation script for flash_script.sh and addon.d.sh
install_magisk() {
cd $MAGISKBIN
# Source the boot patcher
SOURCEDMODE=true
. ./boot_patch.sh "$BOOTIMAGE"
ui_print "- Flashing new boot image"
flash_image new-boot.img "$BOOTIMAGE"
case $? in
1)
abort "! Insufficient partition size"
;;
2)
abort "! $BOOTIMAGE is read only"
;;
esac
./magiskboot cleanup
rm -f new-boot.img
run_migrations
}
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() {
[ -d /postinstall/tmp ] && POSTINST=/postinstall
cd $POSTINST/system
if [ -f bin/su -o -f xbin/su ] && [ ! -f /su/bin/su ]; then
ui_print "- Removing system installed root"
blockdev --setrw /dev/block/mapper/system$SLOT 2>/dev/null
mount -o rw,remount $POSTINST/system
# SuperSU
cd bin
if [ -e .ext/.su ]; then
mv -f app_process32_original app_process32 2>/dev/null
mv -f app_process64_original app_process64 2>/dev/null
mv -f install-recovery_original.sh install-recovery.sh 2>/dev/null
if [ -e app_process64 ]; then
ln -sf app_process64 app_process
elif [ -e app_process32 ]; then
ln -sf app_process32 app_process
fi
fi
# More SuperSU, SuperUser & ROM su
cd ..
rm -rf .pin bin/.ext etc/.installed_su_daemon etc/.has_su_daemon \
xbin/daemonsu xbin/su xbin/sugote xbin/sugote-mksh xbin/supolicy \
bin/app_process_init bin/su /cache/su lib/libsupol.so lib64/libsupol.so \
su.d etc/init.d/99SuperSUDaemon etc/install-recovery.sh /cache/install-recovery.sh \
.supersu /cache/.supersu /data/.supersu \
app/Superuser.apk app/SuperSU /cache/Superuser.apk
elif [ -f /cache/su.img -o -f /data/su.img -o -d /data/su -o -d /data/adb/su ]; then
ui_print "- Removing systemless installed root"
umount -l /su 2>/dev/null
rm -rf /cache/su.img /data/su.img /data/su /data/adb/su /data/adb/suhide \
/cache/.supersu /data/.supersu /cache/supersu_install /data/supersu_install
fi
cd $TMPDIR
}
api_level_arch_detect() {
API=$(grep_get_prop ro.build.version.sdk)
ABI=$(grep_get_prop ro.product.cpu.abi)
if [ "$ABI" = "arm64-v8a" ]; then
ARCH=arm64
ABI32=armeabi-v7a
IS64BIT=true
elif [ "$ABI" = "x86_64" ]; then
ARCH=x64
ABI32=x86
IS64BIT=true
elif [ "$ABI" = "armeabi-v7a" ]; then
ARCH=arm
ABI32=armeabi-v7a
IS64BIT=false
elif [ "$ABI" = "x86" ]; then
ARCH=x86
ABI32=x86
IS64BIT=false
elif [ "$ABI" = "riscv64" ]; then
ARCH=riscv64
ABI32=riscv32
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 data is decrypted
$DATA && [ -d /data/adb ] && touch /data/adb/.rw && rm /data/adb/.rw && DATA_DE=true
$DATA_DE && [ -d /data/adb/magisk ] || mkdir /data/adb/magisk || DATA_DE=false
fi
MAGISKBIN="/data/magisk"
$DATA || MAGISKBIN="/cache/data_adb/magisk"
$DATA_DE && MAGISKBIN="/data/adb/magisk"
}
run_migrations() {
local SHA1
local TARGET
# Legacy app installation
local BACKUP=$MAGISKBIN/stock_boot*.gz
if [ -f $BACKUP ]; then
cp $BACKUP /data
rm -f $BACKUP
fi
# Legacy backup
for gz in /data/stock_boot*.gz; do
[ -f $gz ] || break
SHA1=$(basename $gz | sed -e 's/stock_boot_//' -e 's/.img.gz//')
[ -z $SHA1 ] && break
mkdir /data/magisk_backup_${SHA1} 2>/dev/null
mv $gz /data/magisk_backup_${SHA1}/boot.img.gz
done
# Stock backups
SHA1=
for name in boot dtb dtbo dtbs; do
BACKUP=$MAGISKBIN/stock_${name}.img
[ -f $BACKUP ] || continue
if [ $name = 'boot' ]; then
SHA1=$($MAGISKBIN/magiskboot sha1 $BACKUP)
mkdir /data/magisk_backup_${SHA1} 2>/dev/null
fi
[ -z $SHA1 ] && break
TARGET=/data/magisk_backup_${SHA1}/${name}.img
cp $BACKUP $TARGET
rm -f $BACKUP
gzip -9f $TARGET
done
copy_preinit_files
}
copy_preinit_files() {
local PREINITDIR=$MAGISKTMP/.magisk/preinit
if [ ! -d $PREINITDIR ]; then
ui_print "- Unable to find preinit dir"
return 1
fi
# Copy all enabled sepolicy.rule
for r in /data/adb/modules*/*/sepolicy.rule; do
[ -f "$r" ] || continue
local MODDIR=${r%/*}
[ -f $MODDIR/disable ] && continue
[ -f $MODDIR/remove ] && continue
[ -f $MODDIR/update ] && continue
cat $r
echo
done > $PREINITDIR/sepolicy.rule
}
#################
# Module Related
#################
set_perm() {
chown $2:$3 $1 || return 1
chmod $4 $1 || return 1
local 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
}
boot_actions() { return; }
# Require ZIPFILE to be set
is_legacy_script() {
unzip -l "$ZIPFILE" install.sh | grep -q install.sh
return $?
}
# $1 = MODPATH
set_default_perm() {
set_perm_recursive $1 0 0 0755 0644
set_perm_recursive $1/system/bin 0 2000 0755 0755
set_perm_recursive $1/system/xbin 0 2000 0755 0755
set_perm_recursive $1/system/system_ext/bin 0 2000 0755 0755
set_perm_recursive $1/system/vendor/bin 0 2000 0755 0755 u:object_r:vendor_file:s0
}
# Require OUTFD, ZIPFILE to be set
install_module() {
rm -rf $TMPDIR
mkdir -p $TMPDIR
chcon u:object_r:system_file:s0 $TMPDIR
cd $TMPDIR
setup_flashable
mount_partitions
api_level_arch_detect
# Setup busybox and binaries
if $BOOTMODE; then
boot_actions
else
recovery_actions
fi
# Extract prop file
unzip -o "$ZIPFILE" module.prop -d $TMPDIR >&2
[ ! -f $TMPDIR/module.prop ] && abort "! This zip is not a Magisk module!"
local MODDIRNAME=modules
$BOOTMODE && MODDIRNAME=modules_update
local MODULEROOT=/data/adb/$MODDIRNAME
MODID=$(grep_prop id $TMPDIR/module.prop)
MODNAME=$(grep_prop name $TMPDIR/module.prop)
MODAUTH=$(grep_prop author $TMPDIR/module.prop)
MODPATH=$MODULEROOT/$MODID
# Create mod paths
rm -rf $MODPATH
mkdir -p $MODPATH
chcon u:object_r:system_file:s0 $MODPATH
if is_legacy_script; then
unzip -oj "$ZIPFILE" module.prop install.sh uninstall.sh 'common/*' -d $TMPDIR >&2
# Load install script
. $TMPDIR/install.sh
# Callbacks
print_modname
on_install
[ -f $TMPDIR/uninstall.sh ] && cp -af $TMPDIR/uninstall.sh $MODPATH/uninstall.sh
$SKIPMOUNT && touch $MODPATH/skip_mount
$PROPFILE && cp -af $TMPDIR/system.prop $MODPATH/system.prop
cp -af $TMPDIR/module.prop $MODPATH/module.prop
$POSTFSDATA && cp -af $TMPDIR/post-fs-data.sh $MODPATH/post-fs-data.sh
$LATESTARTSERVICE && cp -af $TMPDIR/service.sh $MODPATH/service.sh
ui_print "- Setting permissions"
set_permissions
else
print_title "$MODNAME" "by $MODAUTH"
print_title "Powered by Magisk"
unzip -o "$ZIPFILE" customize.sh -d $MODPATH >&2
if ! grep -q '^SKIPUNZIP=1$' $MODPATH/customize.sh 2>/dev/null; then
ui_print "- Extracting module files"
unzip -o "$ZIPFILE" -x 'META-INF/*' -d $MODPATH >&2
set_default_perm $MODPATH
fi
# Load customization script
[ -f $MODPATH/customize.sh ] && . $MODPATH/customize.sh
fi
# Handle replace folders
for TARGET in $REPLACE; do
ui_print "- Replace target: $TARGET"
mktouch $MODPATH$TARGET/.replace
done
for TARGET in $REMOVE; do
ui_print "- Remove target: $TARGET"
mkdir -p $(dirname $MODPATH$TARGET) 2>/dev/null
mknod $MODPATH$TARGET c 0 0
done
if $BOOTMODE; then
# Update info for Magisk app
mktouch /data/adb/modules/$MODID/update
rm -rf /data/adb/modules/$MODID/remove 2>/dev/null
rm -rf /data/adb/modules/$MODID/disable 2>/dev/null
cp -af $MODPATH/module.prop /data/adb/modules/$MODID/module.prop
fi
# Copy over custom sepolicy rules
if [ -f $MODPATH/sepolicy.rule ]; then
ui_print "- Installing custom sepolicy rules"
copy_preinit_files
fi
# Remove stuff that doesn't belong to modules and clean up any empty directories
rm -rf \
$MODPATH/system/placeholder $MODPATH/customize.sh \
$MODPATH/README.md $MODPATH/.git*
rmdir -p $MODPATH 2>/dev/null
cd /
$BOOTMODE || recovery_cleanup
rm -rf $TMPDIR
ui_print "- Done"
}
##########
# Presets
##########
# Detect whether in boot mode
[ -z $BOOTMODE ] && ps | grep zygote | grep -qv grep && BOOTMODE=true
[ -z $BOOTMODE ] && ps -A 2>/dev/null | grep zygote | grep -qv grep && BOOTMODE=true
[ -z $BOOTMODE ] && BOOTMODE=false
TMPDIR=/dev/tmp
MAGISKBIN="/data/adb/magisk"