Significantly better AVD support

This commit is contained in:
topjohnwu 2021-08-26 03:09:56 -07:00
parent 0cd99712fa
commit 4771c2810b
8 changed files with 103 additions and 55 deletions

View File

@ -23,9 +23,9 @@ static bool safe_mode = false;
* Setup * * Setup *
*********/ *********/
#define MNT_DIR_IS(dir) (me->mnt_dir == string_view(dir)) #define MNT_DIR_IS(dir) (me->mnt_dir == string_view(dir))
#define SETMIR(b, part) sprintf(b, "%s/" MIRRDIR "/" #part, MAGISKTMP.data()) #define SETMIR(b, part) snprintf(b, sizeof(b), "%s/" MIRRDIR "/" #part, MAGISKTMP.data())
#define SETBLK(b, part) sprintf(b, "%s/" BLOCKDIR "/" #part, MAGISKTMP.data()) #define SETBLK(b, part) snprintf(b, sizeof(b), "%s/" BLOCKDIR "/" #part, MAGISKTMP.data())
#define do_mount_mirror(part, flag) {\ #define do_mount_mirror(part, flag) {\
SETMIR(buf1, part); \ SETMIR(buf1, part); \

View File

@ -91,6 +91,11 @@ static void handle_request_sync(int client, int code) {
case START_DAEMON: case START_DAEMON:
setup_logfile(true); setup_logfile(true);
break; break;
case STOP_DAEMON:
magiskhide_handler(-1, nullptr);
write_int(client, 0);
// Terminate the daemon!
exit(0);
} }
} }
@ -120,6 +125,7 @@ static void handle_request(int client) {
case SQLITE_CMD: case SQLITE_CMD:
case GET_PATH: case GET_PATH:
case MAGISKHIDE: case MAGISKHIDE:
case STOP_DAEMON:
if (!is_root) { if (!is_root) {
write_int(client, ROOT_REQUIRED); write_int(client, ROOT_REQUIRED);
goto done; goto done;

View File

@ -28,6 +28,7 @@ Options:
Advanced Options (Internal APIs): Advanced Options (Internal APIs):
--daemon manually start magisk daemon --daemon manually start magisk daemon
--stop remove all magisk changes and stop daemon
--[init trigger] start service for init trigger --[init trigger] start service for init trigger
Supported init triggers: Supported init triggers:
post-fs-data, service, boot-complete post-fs-data, service, boot-complete
@ -84,6 +85,10 @@ int magisk_main(int argc, char *argv[]) {
int fd = connect_daemon(true); int fd = connect_daemon(true);
write_int(fd, START_DAEMON); write_int(fd, START_DAEMON);
return 0; return 0;
} else if (argv[1] == "--stop"sv) {
int fd = connect_daemon();
write_int(fd, STOP_DAEMON);
return read_int(fd);
} else if (argv[1] == "--post-fs-data"sv) { } else if (argv[1] == "--post-fs-data"sv) {
int fd = connect_daemon(true); int fd = connect_daemon(true);
write_int(fd, POST_FS_DATA); write_int(fd, POST_FS_DATA);

View File

@ -19,7 +19,8 @@ enum : int {
CHECK_VERSION = SYNC_FLAG | 1, CHECK_VERSION = SYNC_FLAG | 1,
CHECK_VERSION_CODE = SYNC_FLAG | 2, CHECK_VERSION_CODE = SYNC_FLAG | 2,
GET_PATH = SYNC_FLAG | 3, GET_PATH = SYNC_FLAG | 3,
SUPERUSER = 4, STOP_DAEMON = SYNC_FLAG | 4,
SUPERUSER = 5,
POST_FS_DATA, POST_FS_DATA,
LATE_START, LATE_START,
BOOT_COMPLETE, BOOT_COMPLETE,

View File

@ -25,14 +25,15 @@ void hide_daemon(int pid, int client) {
#define TMPFS_MNT(dir) (mentry->mnt_type == "tmpfs"sv && str_starts(mentry->mnt_dir, "/" #dir)) #define TMPFS_MNT(dir) (mentry->mnt_type == "tmpfs"sv && str_starts(mentry->mnt_dir, "/" #dir))
void hide_unmount(int pid) { void hide_unmount(int pid) {
if (pid > 0 && switch_mnt_ns(pid)) if (pid > 0) {
return; if (switch_mnt_ns(pid))
return;
LOGD("hide: handling PID=[%d]\n", pid > 0 ? pid : getpid()); LOGD("hide: handling PID=[%d]\n", pid);
}
vector<string> targets; vector<string> targets;
// Unmount dummy skeletons and /sbin links // Unmount dummy skeletons and MAGISKTMP
targets.push_back(MAGISKTMP); targets.push_back(MAGISKTMP);
parse_mnt("/proc/self/mounts", [&](mntent *mentry) { parse_mnt("/proc/self/mounts", [&](mntent *mentry) {
if (TMPFS_MNT(system) || TMPFS_MNT(vendor) || TMPFS_MNT(product) || TMPFS_MNT(system_ext)) if (TMPFS_MNT(system) || TMPFS_MNT(vendor) || TMPFS_MNT(product) || TMPFS_MNT(system_ext))

View File

@ -25,6 +25,11 @@ using namespace std;
} }
void magiskhide_handler(int client, ucred *cred) { void magiskhide_handler(int client, ucred *cred) {
if (client < 0) {
hide_unmount();
return;
}
int req = read_int(client); int req = read_int(client);
int res = DAEMON_ERROR; int res = DAEMON_ERROR;

View File

@ -126,7 +126,7 @@ int exec_command_sync(exec_t &exec, Args &&...args) {
} }
template <class ...Args> template <class ...Args>
int exec_command_sync(Args &&...args) { int exec_command_sync(Args &&...args) {
exec_t exec{}; exec_t exec;
return exec_command_sync(exec, args...); return exec_command_sync(exec, args...);
} }
template <class ...Args> template <class ...Args>

View File

@ -3,16 +3,19 @@
# AVD Magisk Setup # AVD Magisk Setup
##################################################################### #####################################################################
# #
# This script will setup an environment with minimal Magisk that # Support emulator ABI: x86_64 *only*
# the Magisk app will be happy to run properly within the official # Support API level: 23 - 31 (21 and 22 images do not have SELinux)
# emulator bundled with Android Studio (AVD).
# #
# ONLY use this script for developing the Magisk app or root apps # This script will stop zygote, simulate the Magisk start up process
# in the emulator. The constructed Magisk environment is not a # that would've happened before zygote was started, and finally
# fully functional one as if it is running on an actual device. # 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.
# #
# The script assumes you are using x64 emulator images. # This only covers the "core" features of Magisk. Testing magiskinit
# Build binaries with `./build.py binary` before running this script. # and magiskboot require additional setups that are not covered here.
#
# Build everything by `./build.py all` before running this script.
# #
##################################################################### #####################################################################
@ -29,16 +32,13 @@ mount_sbin() {
if [ ! -f /system/build.prop ]; then if [ ! -f /system/build.prop ]; then
# Running on PC # Running on PC
cd "$(dirname "$0")/.." cd "$(dirname "$0")/.."
adb push native/out/x86_64/busybox native/out/x86_64/magiskinit \ adb push native/out/x86_64/busybox out/app-debug.apk scripts/emulator.sh /data/local/tmp
native/out/x86_64/magisk scripts/emulator.sh /data/local/tmp
adb shell sh /data/local/tmp/emulator.sh adb shell sh /data/local/tmp/emulator.sh
exit 0 exit 0
fi fi
cd /data/local/tmp cd /data/local/tmp
chmod 777 busybox chmod 755 busybox
chmod 777 magiskinit
chmod 777 magisk
if [ -z "$FIRST_STAGE" ]; then if [ -z "$FIRST_STAGE" ]; then
export FIRST_STAGE=1 export FIRST_STAGE=1
@ -52,20 +52,34 @@ if [ -z "$FIRST_STAGE" ]; then
fi fi
fi fi
# Remove previous setup if exist pm install -r $(pwd)/app-debug.apk
pgrep magiskd >/dev/null && pkill -9 magiskd
[ -f /sbin/magisk ] && umount -l /sbin # Extract files from APK
[ -f /system/bin/magisk ] && umount -l /system/bin unzip -oj app-debug.apk 'lib/x86_64/*' 'lib/x86/libmagisk32.so' -x 'lib/x86_64/busybox.so'
if [ -d /dev/magisk ]; then for file in lib*.so; do
umount -l /dev/magisk 2>/dev/null chmod 755 $file
rm -rf /dev/magisk mv "$file" "${file:3:${#file}-6}"
done
# Stop zygote (and previous setup if exists)
magisk --stop 2>/dev/null
stop
if [ -d /dev/avd-magisk ]; then
umount -l /dev/avd-magisk 2>/dev/null
rm -rf /dev/avd-magisk 2>/dev/null
fi fi
# SELinux stuffs # SELinux stuffs
ln -sf ./magiskinit magiskpolicy ln -sf ./magiskinit magiskpolicy
./magiskpolicy --live --magisk if [ -f /vendor/etc/selinux/precompiled_sepolicy ]; then
./magiskpolicy --load /vendor/etc/selinux/precompiled_sepolicy --live --magisk
elif [ -f /sepolicy ]; then
./magiskpolicy --load /sepolicy --live --magisk
else
./magiskpolicy --live --magisk
fi
BINDIR=/sbin MAGISKTMP=/sbin
# Setup bin overlay # Setup bin overlay
if mount | grep -q rootfs; then if mount | grep -q rootfs; then
@ -81,13 +95,11 @@ if mount | grep -q rootfs; then
elif [ -e /sbin ]; then elif [ -e /sbin ]; then
# Legacy SAR # Legacy SAR
mount_sbin mount_sbin
if ! grep -q '/sbin/.magisk/mirror/system_root' /proc/mounts; then mkdir -p /dev/sysroot
mkdir -p /sbin/.magisk/mirror/system_root block=$(mount | grep ' / ' | awk '{ print $1 }')
block=$(mount | grep ' / ' | awk '{ print $1 }') [ $block = "/dev/root" ] && block=/dev/block/dm-0
[ $block = "/dev/root" ] && block=/dev/block/dm-0 mount -o ro $block /dev/sysroot
mount -o ro $block /sbin/.magisk/mirror/system_root for file in /dev/sysroot/sbin/*; do
fi
for file in /sbin/.magisk/mirror/system_root/sbin/*; do
[ ! -e $file ] && break [ ! -e $file ] && break
if [ -L $file ]; then if [ -L $file ]; then
cp -af $file /sbin cp -af $file /sbin
@ -97,25 +109,43 @@ elif [ -e /sbin ]; then
mount -o bind $file $sfile mount -o bind $file $sfile
fi fi
done done
umount -l /dev/sysroot
rm -rf /dev/sysroot
else else
# Android Q+ without sbin, use overlayfs # Android Q+ without sbin
BINDIR=/dev/magisk/upper MAGISKTMP=/dev/avd-magisk
mkdir /dev/magisk mkdir /dev/avd-magisk
mount -t tmpfs -o 'mode=0755' tmpfs /dev/magisk mount -t tmpfs -o 'mode=0755' tmpfs /dev/avd-magisk
chcon u:object_r:system_file:s0 /dev/magisk
mkdir /dev/magisk/upper
mkdir /dev/magisk/work
./magisk --clone-attr /system/bin /dev/magisk/upper
mount -t overlay overlay -o lowerdir=/system/bin,upperdir=/dev/magisk/upper,workdir=/dev/magisk/work /system/bin
fi fi
# Magisk stuffs # Magisk stuffs
cp -af ./magisk $BINDIR/magisk mkdir -p /data/adb/magisk 2>/dev/null
chmod 755 $BINDIR/magisk unzip -oj app-debug.apk 'assets/*' -x 'assets/chromeos/*' -d /data/adb/magisk
ln -s ./magisk $BINDIR/su mkdir /data/adb/modules 2>/dev/null
ln -s ./magisk $BINDIR/resetprop
ln -s ./magisk $BINDIR/magiskhide
mkdir -p /data/adb/modules 2>/dev/null
mkdir /data/adb/post-fs-data.d 2>/dev/null mkdir /data/adb/post-fs-data.d 2>/dev/null
mkdir /data/adb/services.d 2>/dev/null mkdir /data/adb/services.d 2>/dev/null
$BINDIR/magisk --daemon
for file in magisk32 magisk64 magiskinit; do
chmod 755 ./$file
cp -af ./$file $MAGISKTMP/$file
cp -af ./$file /data/adb/magisk/$file
done
cp -af ./magiskboot /data/adb/magisk/magiskboot
cp -af ./busybox /data/adb/magisk/busybox
ln -s ./magisk64 $MAGISKTMP/magisk
ln -s ./magisk $MAGISKTMP/su
ln -s ./magisk $MAGISKTMP/resetprop
ln -s ./magisk $MAGISKTMP/magiskhide
ln -s ./magiskinit $MAGISKTMP/magiskpolicy
mkdir -p $MAGISKTMP/.magisk/mirror
mkdir $MAGISKTMP/.magisk/block
touch $MAGISKTMP/.magisk/config
# Boot up
$MAGISKTMP/magisk --post-fs-data
while [ ! -f /dev/.magisk_unblock ]; do sleep 1; done
rm /dev/.magisk_unblock
start
$MAGISKTMP/magisk --service