Android 10: Emulation of Magisk/SuperSU on an AOSP AVD
This article aims to:
- describe the process for installing SuperSU or Magisk on an Android AOSP 10 Virtual Device (AVD) using the official Emulator, which is provided as part of the Android SDK tools
- provide insight into the behaviour of SuperSU/Magisk
su
binaries vs AOSP's defaultsu
binary - highlight constraints that have been implemented for Android Builds starting from 9 and onwards, particularly in relation to partition layouts and the init process
- highlight the limitations of working with/installing Magisk/SuperSU using Android’s SDK emulator
Limitations/Constraints
Android Studio SDK Emulator & AVD
- The Android Virtual Device (AVD) that will used, runs using the Android SDK with an
Atom x64 Image
. - The Android Open Source Platform (AOSP) 10 image/AVD, is classified as a non-A/B device system.
- From Android 9 onwards,
system-as-root
partitioning was introduced along with anext4 deduped
filesystem. For further details on these changes, refer to Appendix 1. - Emulation of physical device modes, such as
recovery/fastboot/bootloader
etc. are not supported. - AOSP 10 builds do not come bundled with Google Play Services/PlayStore.
Google Inc.
equivalents of these are available, butsu
mode on these devices is not enabled.
Limitations Applicable to Emulation of Magisk/SuperSU
I was unable to find references to emulated devices in the official installation guide for Magisk, as published by the developer, John Wu. All the installation methods outlined required some form of flashing
, via either of the following recovery mode, custom recovery, boot image patching
.
The final build and install of MagiskSU functions as expected. Installation of Magisk Manager modules is possible, however, the modules do not function as expected, and this is an area requiring further discovery. As such, addressing issues related to Magisk modules is out of scope.
For both SuperSU/Magisk, daemon processes will not persist after rebooting the AVD, i.e. you will need to manually restart backend daemons after rebooting the AVD. There are likely to be methods to launch the daemons via an init process, but this is not in scope for this article.
Pre-requisites for Magisk/SuperSU
If you’re familiar with system changes implemented in Android 9/10, Android SDKs and AVDs, then you can start following on from the next section and adapt instructions to suit your development environment.
If you are a beginner and have never worked with Android SDKs/AVDs or Android 9/10, then before proceeding, consider reading the Appendices that form part of this article.
Target Virtual Device Details
AVD Name: aosp10_sandbox
SDK Image/Platform: Intel x86 Atom System Image
ABI: x86_64
API Level: 29
Revision: 7
SELinux Policy
First things first, we are dealing with an SELinux (Security Enhanced Linux) system, which in context for this article, can succinctly be described by the following reference:
that the SELinux policy is in effect and things that it doesn’t want to allow won’t be allowed
- To confirm that SELinux is enabled by default on the target AVD, start the device using command:
emulator -avd aosp10_sandbox
- Run the following to see the current policy status:
adb root
adb shell getenforce
-->
Enforcing
- To allow violations to be accepted (but still be logged), we would need to set the policy to
permissive
as follows :
adb shell "setenforce 0"
- This would toggle the policy from
Enforcing (1)
toPermissive (0)
:
adb shell getenforce
-->
Permissive
Launch AVD with SELinux Policy as permissive by Default
SuperSU/MagiskSU will require the SELinux policy to be set to permissive
.
- For an AVD that has been created but has never been started/launched since creation, then start the AVD in
permissive
mode as follows:
emulator -avd aosp10_sandbox -selinux permissive
- For an AVD that has already been created and launched without explicitly passing the
-selinux permissive
option, then the following can be used to restart the emulator inpermissive
mode:
emulator -avd aosp10_sandbox -selinux permissive -no-snapshot-load
Confirm AVD Details
Use adb
to obtain/confirm some info about AVD/AOSP build.
- Start the
adb
with root permissions by issuing:
adb root
- Issuing an
adb shell getprop
lists all the properties for the Android AVD build. We will be building binaries later on, so we should confirm our target device's build architecture by running:
adb shell "getprop ro.product.cpu.abi"
--> x86_64
- Confirm we are running Non-A/B system:
adb shell getprop ro.build.ab_update
--> false
- Confirm Android release and SDK version:
adb shell getprop ro.system.build.version.release
--> 10
adb shell getprop ro.system.build.version.sdk
-->
29
- Display location of existing
su
binary:
adb shell "which su"
--> /system/xbin/su
- What else is at location
/system/xbin/su
?:
adb shell "ls -laR /system/xbin"
-->
-rwsr-x--- 1 root shell 11528 2019-08-02 15:35 su
- This is the location where will later prepare for hosting SuperSU binaries/modules.
Installing SuperSU
The following instructions assume the AVD is in a “fresh” state, i.e, a “Wipe Data” has been performed and that the AVD’s SELinux policy is permissive
.
Download files required for SuperSU version 2.82-SR5:
- superSU-v2.82-SR5–20171001224502.zip, this zip contains the binaries required for various platform architectures along with corresponding
su
binary/modules. The XDA forum thread contains further info. - supersu-2–82-SR5-android-apk. The APK will work with the
su
daemon and fulfil/deny application requests forsu
access
Install and Run SuperSU Daemon
- Always ensure
adb
is running with root permissions when launching new host environment shells (such asPowershell/Command Prompt
) :
adb root
- Extract the folder
x64
(for our build's architecture), from withinSR5-SuperSU-v2.82-SR5-20171001224502.zip
. - Since we’re running Android 10, we cannot mount/remount
/system
or/
as writeable due to Android 10's system-as-root build properties and the ramdisk init process (refer to Appendix 1). - The root file system is mounted as
ro - readonly
adb shell "cat /proc/mounts | grep -i ' / '"
-->
dev/block/dm-2 / ext4 ro,secla......
- However, we have the ability create a read/write
tmpfs
filesystem, and mount this on/system/xbin
- Create
tmpfs
filesystem 15MB size (enough space for the modules) with mount point/system/xbin
adb shell "mount -t tmpfs -o size=15M tmpfs /system/xbin"
- Check mount:
adb shell "cat /proc/mounts | grep /system/xbin"
-->
tmpfs /system/xbin tmpfs rw,seclabel,relatime,size=15360k 0 0
- Upload contents of folder
x64\
(extracted from zip file mentioned previously) to/system/xbin
. Assuming the contents were extracted toc:\temp\x64
, and usingWindows Powershell
, we can upload as follows:
cd c:\temp\x64
adb push .\ "/system/xbin/"
-->
.\: 5 files pushed, 0 skipped. 85.6 MB/s (872152 bytes in 0.010s)
- Check that files have been uploaded to correct target:
adb shell "ls -l /system/xbin"
-->
libsupol.so
su
suinit
sukernel
supolicy
- Install
SuperSU-v2.82-SR5.apk
, as downloaded above. You can do this by dragging and dropping the apk from your local machine to the AVD, or run the following (assuming apk has been downloaded toc:\temp\SuperSU-v2.82-SR5.apk
):
cd c:\temp
adb install SuperSU-v2.82-SR5.apk
-->
Performing Streamed Install
Success
- Launch
su
in daemon mode:
adb shell "nohup /system/xbin/su 0 su --daemon &"
- To confirm that the daemon is running on the AVD, run the following to search active processes:
adb shell "ps -ef | grep daemonsu"
-->
..
..daemonsu:mount:master
..daemonsu:master
..
Test SuperSU Works as Expected from within AVD
- Run SuperSU app from within the AVD.
- When you first launch SuperSU from within the AVD, ensure to respond to prompts as shown below.
- The tested combination of the zip/apk referenced in the download requirements above, worked as expected.
- Accepting requests from SuperSU to perform updates may introduce incompatibilities with the SU binary and SuperSU Apk.
- To test if SuperSU correctly manages app requests for access, I downloaded one of my favourite File Explorers (X-plore) from Apk Mirror.
- Follow this link and use the site’s search feature to find and download latest version of X-plore.
- To install, use drag and drop from host to AVD, or run the following (I’ve saved the downloaded apk with name and location
c:\temp\Xplore_4.20.04-42004.apk
):
cd c:\temp
adb install Xplore_4.20.04-42004.apk
-->
Performing Streamed Install
Success
- Go back into your AVD, locate
X-plore
and open the app. - Select
Allow
when prompted for permissions to access photos/media/files on the device. - Click the
root
(/
) hierarchy from within X-plore to view the root file system (which requiressu
privileges). - You will be prompted by SuperSU to grant/deny
su
access for X-plore.
Installing Magisk
If you’ve gone through the SuperSU install, I suggest that you perform a “Wipe Data” against the AVD before proceeding.
The following sections relating to Magisk, were tested using build scripts from Magisk Git Repo.
Setup Python, JDK and Environment
- According to the official repo, the build/install scripts require Python version 3.6+.
- Install jdk8.
- Ensure your
JAVA_HOME
environment variable is set correctly and is appended to you System EnvironmentPATH
to include Javabin
directory. For example, on Windows, if your JDK installation path isC:\Java\jdk1.8.0_251
, then setJAVA_HOME
to this value and add%JAVA_HOME%\bin
to yourPATH
. - Create a new
ANDROID_HOME
environment variable, which should be set to your Android SDK installation location. Refer to Appendix 3 for further details. - Python package
colorama
is required and can be installed using:
pip install colorama
Clone Git Repo Tree
- Clone the official git repo, Magisk Git Repo (I’m performing the clone on my machine from directory
c:\temp\repos
):
cd C:\temp\repos
git clone --recurse-submodules https://github.com/topjohnwu/Magisk.git
- After the clone is done, local repo components will be under parent
C:\temp\repos\Magisk
.
Build Binaries
- Edit repo file
config.prop.sample
and update the parameters for the lines shown below:
# The version name and version code of Magisk
version=20.4
versionCode=20400
# The version name and version code of Magisk Manager
appVersion=7.5.1
appVersionCode=267
- Since we are building from source, the above
versions/version codes
can correspond to the latest version numbers listed at the repo'sreleases
section. You can use your own custom numbers/codes, but the build script performsregex
checks against these and expects parameter values to satisfy a certain format. - Save the file and rename it to
config.prop
. - Open a command/shell prompt at local repo’s root folder, containing
build.py
, and run the following commands sequentially:
python build.py ndk
python build.py all
- Once the above commands have run to completion, the required binaries will be built and are located within the local repo hierarchy at location
`C:\temp\repos\Magisk\native\out\{architecture}
. - Apks are stored at
C:\temp\repos\Magisk\out
.
Magisk Binaries and SU Daemon
The script which performs the installation of binaries and initialises the MagiskSU daemon on the target AVD, is located within local repo at C:\temp\repos\Magisk\scripts\emulator.sh
. This is a bash
shell script.
To execute the script, follow the procedure below for your corresponding host OS.
Linux
- The script can be executed directly from the host:
cd <repo_root_path>/scripts
chmod 755 emulator.sh
./emulator.sh
adb shell "mkdir -p /data/adb/magisk"
adb shell "cp /data/local/tmp/busybox /data/adb/magisk/"
adb push scripts/util_functions.sh /data/adb/magisk/
Windows
- For installation from a
Windows
host (usingPowershell
), we first useadb
to push themagiskinit64
binary, along other with other required scripts, to the targetx86_64
AVD:
cd C:\temp\repos\Magisk
adb root
adb push native\out\x86\busybox scripts\emulator.sh /data/local/tmp
adb push native\out\x86\magiskinit64 /data/local/tmp/magiskinit
adb shell "mkdir -p /data/adb/magisk"
adb shell "cp /data/local/tmp/busybox /data/adb/magisk/"
adb push scripts\util_functions.sh /data/adb/magisk/
- After the successful completion of the above, all necessary binaries (including installer
emulator.sh
) will have been pushed to target directory on AVD:/data/local/tmp
. - Now run the following to execute
emulator.sh
on the target AVD:
adb shell sh /data/local/tmp/emulator.sh
Confirm MagiskSU Daemon Status
To confirm that MagiskSU is running on the target AVD, run:
adb shell "ps -ef | grep -i magisk"
-->
root ..... 00:00:00 magiskd
Install Magisk Manager APK to AVD
When we previously used build.py
, we specified all
as an input parameter. This not only generates output binaries required. The command also generates the necessary Magisk Manager APK at local repo location C:\temp\repos\Magisk\out
. The Magisk Manager apk is located within this directory, and by default, is named app-debug.apk
.
- Install the apk using
adb
:
cd C:\temp\repos\Magisk\out
adb root
adb install app-debug.apk
-->
Performing Streamed Install
Success
- Magisk Manager should now visible from within the AVD
Testing Magisk
Leveraging off the procedure used to test SuperSU, we can run a similar test for MagiskSU
- Download X-plore from Apk Mirror.
- To install, use drag and drop from host to AVD, or run the following (I’ve saved the downloaded apk with name and location
c:\temp\Xplore_4.20.04-42004.apk
):
cd c:\temp
adb install Xplore_4.20.04-42004.apk
-->
Performing Streamed Install
Success
- Now go back into your AVD, locate
X-plore
and click to launch the app. - Select
Allow
when prompted for permissions to access photos/media/files on the device. - Click the
root
(/
) hierarchy to view the root file system (which requiressu
privileges). - You will be prompted by MagiskSU to allow
su
access.
Final Comments
Hopefully you’ve found this article interesting and enjoyed the walk-thru.
As mentioned earlier, Magisk Manager modules install fine, but don’t function. As of now, more discovery is required to determine if there is a possibility of getting the modules working.
First thing I did after completing the setup, was downloading Google Play Store alternatives, F-Droid and Aptiode. You will also find that Apk Mirror is another excellent source for app downloads. The AVD serves as an excellent environment for trialling apps and gaining an understanding of Android.
Don’t forget that a reboot of the AVD will kill the su
daemon, so you will need to manually start it again with the respective commands for SuperSU /MagiskSU.
Appendix 1: Android 10 Partitions/File System
When I first downloaded SDK platform images of Android 10 (API 29), I was keen to quickly get root (su
) access and start remounting system mount points as writeable
for both, Google Inc.
and AOSP
builds. The Google Inc. build was completely locked down with no su
access and limited to read-only mounts. The AOSP build came with su
access, but even as an su
user, my attempts to override the mount behaviour for system/rootfs proved to be unsuccessful, including classic methods used in the past (adb shell
, remount
, .etc)
After some digging around, it became apparent that from Android 9 onwards, there were some architecture/design changes to the build. These changes included system-as-root
partition layout, ramdisk/init
process and implementation of a non-writeable filesystem (ext4 deduplicated
). The filesystem change was broadcasted by the developer of Magisk
via this tweet.
So, a brief overview describing the partition layout/init process for Android 10 follows.
From my interpretation of the official documentation, when Android 10 is compiled from source, it generates build artifacts into several locations. Amongst these are $TARGET_SYSTEM_OUT
(aka system/
), $TARGET_ROOT_OUT
(aka /
or ramdisk.img
). These components are what make up the final system.img
.
The below screenshot, taken from official Android documentation for Partition Layout for Non-A/B Devices shows the layout for system.img
for pre and post system-as-root
:
Android 10, Ramdisk init Stages
The following is a description Ramdisk stages, as taken from Android Official Documentation on Ramdisk.
In Android 10:
- the first stage ramdisk contains the first stage init binary (which performs early mounting as specified by fstab entries) and vendor fstab files.
- For devices with a boot-ramdisk (non-A/B), first stage init is a static executable located at
/init
. These devices mountsystem.img
as/system
, then perform a switch root operation to move the mount at/system
to/
. The contents of the ramdisk are freed after mounting has completed. - After first stage init finishes, it executes
/system/bin/init
with theselinux_setup
argument to compile and load SELinux onto the system - Finally, init executes
/system/bin/init
again with thesecond_stage
argument. At this point, the main phase of init runs and continues the boot process using theinit.rc
scripts.
Appendix 2: Download and Install Android Studio
If you do not have Studio installed then:
- Download from https://developer.android.com/studio
- Start of on a clean slate and deselect
Android Virtual Device
during the installation process
- After Installation, launch Android Studio and when prompted choose the appropriate setting based on your requirements for studio settings
- After this, you will be prompted with a “Welcome” and then onto
installation type
selection. - Select
Custom
- When prompted for
default JDK location
, leave the default setting (which uses the embedded JDK installed by Android Studio) - Select you
UI Theme
- When at the
SDK Component Setup
, go for the following options
and make a note of where the default SDK location path will be installed to, in my case running windows 10 %USERPROFILE%\AppData\Local\Android\Sdk
is the default. Where %USERPROFILE
on windows 10 is C:\Users\<username>
.
https://developer.android.com/studio/command-line/variables
- Choose defaults for HAXM
- Keep selecting next, then
verify settings
and go on until you have finished the installation - After the Android Studio Initial Window Menu appears
Appendix 3: Configuring Android Studio/SDK Platform
- Choose the
Configure
- Then
SDK Manager
and select config forSDK Platforms
as follows
- Once you press
Apply
- Now click on
SDK Tools
to configure
- Click
OK
and when prompted withLicence Agreement
, accept and continue - It will start download components. Wait until it’s done, then hit
finish
AVD/SDK Environment Variables and Paths
Getting back to an earlier point regarding making a note of the location where we installed the sdk to…in my case it was %USERPROFILE%\AppData\Local\Android\Sdk
which is the root path for SDK install for Windows 10.
Create a System Variable ANDROID_SDK_ROOT
and set its value to %USERPROFILE%\AppData\Local\Android\Sdk
.
To make sure our avdmanager, emulator, adb
can be invoked with fully wqualifyed paths from command line, add the following entries to you System Path
environment variable:
%ANDROID_SDK_ROOT%\emulator
%ANDROID_SDK_ROOT%\platform-tools
%ANDROID_SDK_ROOT%\tools\bin
AVD configuration and data files can be located at :
$USERPROFILE/.android/
$USERPROFILE/.android/avd/
Appendix 4: Create Target AOSP 10 Virtual Device
Back to our Android Studio Welcome menu window. To create an AVD named aosp10_sandbox
:
- click
Configure
gear - select
AVD Manager
- Click on
Create Virtual Device
- On the Virtual Device Configuration hardware config, select device that does not have the Play Store icon in the column