### Build System: Initial Setup and Full Build Source: https://context7.com/topjohnwu/magisk/llms.txt Use the Python-based build system to manage the build process. './build.py ndk' is for initial setup, downloading and installing the custom NDK. './build.py all' builds both native binaries and the Magisk APK. ```bash # Initial setup: download and install the custom NDK (ONDK) ./build.py ndk # Build everything: native binaries + Magisk APK ./build.py all ``` -------------------------------- ### Service Boot Script Example Source: https://context7.com/topjohnwu/magisk/llms.txt The service.sh script runs non-blocking in the late_start service, making it suitable for most use cases. Use MODDIR to always get the module directory. ```shell # /data/adb/modules/my_module/service.sh # Runs non-blocking in late_start service — recommended for most use cases MODDIR=${0%/*} # Always use this to get the module directory # Wait until the device has fully booted before doing anything until [ "$(resetprop sys.boot_completed)" = "1" ]; do sleep 1 done # Apply a system property resetprop -n ro.config.notification_sound MySound.ogg # Load a custom kernel module insmod "${MODDIR}/system/lib/modules/v4l2loopback.ko" # Start a background service binary "${MODDIR}/system/bin/myservice" & ``` -------------------------------- ### Post-FS-Data Boot Script Example Source: https://context7.com/topjohnwu/magisk/llms.txt The post-fs-data.sh script runs blocking before Zygote starts. Keep it fast to avoid exceeding the 35s script limit. Use resetprop -n to avoid deadlocking init. ```shell # /data/adb/modules/my_module/post-fs-data.sh # Runs BLOCKING before Zygote starts — keep it fast (35s script limit, 40s total) # WARNING: use resetprop -n instead of setprop to avoid deadlocking init MODDIR=${0%/*} # Patch a property before any app sees it resetprop -n ro.debuggable 1 # Dynamically skip mounting the module's system folder if [ "$(resetprop ro.build.version.sdk)" -lt 28 ]; then touch "${MODDIR}/skip_mount" fi ``` -------------------------------- ### Custom .rc Script Example with ${MAGISKTMP} Source: https://github.com/topjohnwu/magisk/blob/master/docs/guides.md An example of a custom `.rc` script that utilizes the `${MAGISKTMP}` variable to reference files placed in Magisk's temporary filesystem. This script demonstrates loading a kernel module and starting a service. ```rc # Use ${MAGISKTMP} to refer to Magisk's tmpfs directory on early-init setprop sys.example.foo bar insmod ${MAGISKTMP}/libfoo.ko start myservice service myservice ${MAGISKTMP}/myscript.sh oneshot ``` -------------------------------- ### Download and Install NDK Source: https://github.com/topjohnwu/magisk/blob/master/docs/build.md Use the build script to download and install the necessary NDK for Magisk development. ```bash ./build.py ndk ``` -------------------------------- ### Install Nightly Rust Toolchain and Components Source: https://github.com/topjohnwu/magisk/blob/master/docs/build.md Install the official nightly Rust toolchain and necessary components for IDE integration, even if not directly used for building. ```bash rustup toolchain install nightly # Add some components that is also included in ONDK rustup +nightly component add rust-src clippy ``` -------------------------------- ### Magisk Module Installer Customization (customize.sh) Source: https://context7.com/topjohnwu/magisk/llms.txt Demonstrates how to use the `customize.sh` script within a Magisk module to customize the installation process, including skipping default extraction, manually extracting files, installing libraries, and replacing directories. ```bash # customize.sh — optional installer customization script (sourced by module_installer.sh) # Available variables: MAGISK_VER, MAGISK_VER_CODE, BOOTMODE, MODPATH, TMPDIR, # ZIPFILE, ARCH, IS64BIT, API # Skip the default install (take full control) SKIPUNZIP=1 # Manually extract only what you need unzip -o "$ZIPFILE" 'system/*' -d "$MODPATH" # Install ABI-specific library case "$ARCH" in arm64) cp "$TMPDIR/lib/arm64/libfoo.so" "$MODPATH/system/lib64/libfoo.so" ;; arm) cp "$TMPDIR/lib/arm/libfoo.so" "$MODPATH/system/lib/libfoo.so" ;; esac # Replace an entire folder (creates .replace sentinel file) REPLACE=" /system/app/GoogleCamera /system/app/Bloatware " ``` -------------------------------- ### Skip Default Installation Steps in customize.sh Source: https://github.com/topjohnwu/magisk/blob/master/docs/guides.md Declare SKIPUNZIP=1 in `customize.sh` to prevent the default installation process and handle all installation steps within your `customize.sh` script. ```shell SKIPUNZIP=1 ``` -------------------------------- ### Build System: Install on Emulator Source: https://context7.com/topjohnwu/magisk/llms.txt Temporarily install Magisk on a running emulator (non-persistent) using './build.py emulator /path/to/Magisk.apk'. ```bash # Temporarily install Magisk on a running emulator (non-persistent) ./build.py emulator /path/to/Magisk.apk ``` -------------------------------- ### Magisk Utility Tool Usage Source: https://github.com/topjohnwu/magisk/blob/master/docs/tools.md The main magisk binary acts as a utility tool. Use '--list' to see available applets or '--install-module' to install a module zip. For advanced operations, '--daemon' starts the magisk daemon. ```bash Usage: magisk [applet [arguments]...] or: magisk [options]... Options: -c print current binary version -v print running daemon version -V print running daemon version code --list list all available applets --remove-modules [-n] remove all modules, reboot if -n is not provided --install-module ZIP install a module zip file Advanced Options (Internal APIs): --daemon manually start magisk daemon --stop remove all magisk changes and stop daemon --[init trigger] callback on init triggers. Valid triggers: post-fs-data, service, boot-complete, zygote-restart --unlock-blocks set BLKROSET flag to OFF for all block devices --restorecon restore selinux context on Magisk files --clone-attr SRC DEST clone permission, owner, and selinux context --clone SRC DEST clone SRC to DEST --sqlite SQL exec SQL commands to Magisk database --path print Magisk tmpfs mount path --denylist ARGS denylist config CLI --preinit-device resolve a device to store preinit files Available applets: su, resetprop ``` ```bash Usage: magisk --denylist [action [arguments...] ] Actions: status Return the enforcement status enable Enable denylist enforcement disable Disable denylist enforcement add PKG [PROC] Add a new target to the denylist rm PKG [PROC] Remove target(s) from the denylist ls Print the current denylist exec CMDs... Execute commands in isolated mount namespace and do all unmounts ``` -------------------------------- ### Build System: Rust Toolchain Setup Source: https://context7.com/topjohnwu/magisk/llms.txt Setup rustup to use the bundled ONDK Rust toolchain for IDE support by linking the toolchain and setting it as the default. Create a cargo wrapper for JetBrains IDE compatibility. ```bash # Setup rustup to use the bundled ONDK Rust toolchain for IDE support rustup toolchain link magisk "$ANDROID_HOME/ndk/magisk/toolchains/rust" rustup default magisk # Create the cargo wrapper for JetBrains IDE compatibility ./build.py rustup ~/.cargo/wrapper ``` -------------------------------- ### Install Magisk Module from Shell Source: https://context7.com/topjohnwu/magisk/llms.txt Install a Magisk module directly from the command line using an ADB shell. Provide the full path to the module's ZIP file. ```bash # Install a module zip directly from the shell magisk --install-module /sdcard/Download/my_module.zip ``` -------------------------------- ### Create Rust Toolchain Wrapper Source: https://github.com/topjohnwu/magisk/blob/master/docs/build.md Create a wrapper cargo bin directory to work around rustup limitations, recommended for IDE setup. ```bash # We choose ~/.cargo/wrapper here as an example (and a good recommendation) # Pick any path you like, you just need to use this path in the next step ./build.py rustup ~/.cargo/wrapper ``` -------------------------------- ### Install Magisk on Emulator Source: https://github.com/topjohnwu/magisk/blob/master/docs/faq.md Temporarily install Magisk on a running emulator accessible via ADB. This installation is not persistent and will be lost after a reboot. Re-execute the script to simulate a reboot. The emulator must have SELinux enabled. ```bash ./build.py emulator ``` -------------------------------- ### Overlay Directory Structure Example Source: https://github.com/topjohnwu/magisk/blob/master/docs/guides.md Illustrates the placement of files within the `overlay.d` directory for Magisk's root overlay system. Custom scripts and files are placed here to be injected or replaced in the system's root directory. ```text ramdisk │ ├── overlay.d │ ├── sbin │ │ ├── libfoo.ko <--- These 2 files will be copied │ │ └── myscript.sh <--- into Magisk's tmpfs directory │ ├── custom.rc <--- This file will be injected into init.rc │ ├── res │ │ └── random.png <--- This file will replace /res/random.png │ └── new_file <--- This file will be ignored because │ /new_file does not exist ├── res │ └── random.png <--- This file will be replaced by │ /overlay.d/res/random.png ├── ... ├── ... /* The rest of initramfs files */ │ ``` -------------------------------- ### Get Magisk Version Information Source: https://context7.com/topjohnwu/magisk/llms.txt Retrieve the currently installed Magisk version string or version code. The `-v` flag provides a human-readable version, while `-V` provides a numerical version code. ```bash # Print currently running Magisk version / version code magisk -v # e.g. "v30.7:MAGISK:R" magisk -V # e.g. "30700" ``` -------------------------------- ### Build System: Build for Specific ABI Source: https://context7.com/topjohnwu/magisk/llms.txt Build native binaries for a specific ABI using the '--abis' flag, for example, './build.py binary --abis arm64-v8a'. ```bash # Build for a specific ABI ./build.py binary --abis arm64-v8a ``` -------------------------------- ### Magisk Module Installer Structure Source: https://github.com/topjohnwu/magisk/blob/master/docs/guides.md This is the basic structure of a Magisk module zip file, including optional files for recovery flashing. ```plaintext module.zip │ ├── META-INF <--- Only needed for flashing in recovery │ └── com │ └── google │ └── android │ ├── update-binary <--- The module_installer.sh you downloaded │ └── updater-script <--- Should only contain the string "#MAGISK" │ ├── customize.sh <--- (Optional, more details later) │ This script will be sourced by update-binary ├── ... ├── ... /* The rest of module's files */ │ ``` -------------------------------- ### Magisk Module Update JSON Source: https://context7.com/topjohnwu/magisk/llms.txt Example structure for the JSON file served at the `updateJson` URL, providing version details and download links for module updates. ```json // Update JSON served at updateJson URL { "version": "v1.1", "versionCode": 2, "zipUrl": "https://example.com/my_module/my_module-v1.1.zip", "changelog": "https://example.com/my_module/changelog.md" } ``` -------------------------------- ### resetprop Source: https://github.com/topjohnwu/magisk/blob/master/docs/tools.md The `resetprop` applet is an advanced utility for manipulating system properties, allowing users to get, set, delete, or load properties from files. ```APIDOC ## resetprop ### Description An applet of `magisk`. An advanced system property manipulation utility. Check the [Resetprop Details](details.md#resetprop) for more background information. ### Usage ``` Usage: resetprop [flags] [options...] ``` ### Options - **-h, --help**: Show this message. - **(no arguments)**: Print all properties. - **NAME**: Get property NAME. - **NAME VALUE**: Set property entry NAME with VALUE. - **--file FILE**: Load properties from FILE. - **--delete NAME**: Delete property NAME. ### Flags - **-v**: Print verbose output to stderr. - **-n**: Set properties without going through `property_service`. (This flag only affects `setprop`). - **-p**: Read/write properties from/to persistent storage. (This flag only affects `getprop` and `delprop`). ``` -------------------------------- ### Build All Magisk Components Source: https://github.com/topjohnwu/magisk/blob/master/docs/build.md Build the entire Magisk project to create the final Magisk APK. ```bash ./build.py all ``` -------------------------------- ### su Source: https://github.com/topjohnwu/magisk/blob/master/docs/tools.md The `su` applet is the MagiskSU entry point, providing the familiar `su` command functionality with additional options for privilege escalation and environment control. ```APIDOC ## su ### Description An applet of `magisk`, the MagiskSU entry point. This is the standard `su` command with enhanced capabilities. ### Usage ``` Usage: su [options] [-] [user [argument...]] ``` ### Options - **-c, --command COMMAND**: Pass COMMAND to the invoked shell. - **-g, --group GROUP**: Specify the primary group. - **-G, --supp-group GROUP**: Specify a supplementary group. The first specified supplementary group is also used as a primary group if the option `-g` is not specified. - **-Z, --context CONTEXT**: Change SELinux context. - **-t, --target PID**: PID to take mount namespace from. - **-h, --help**: Display this help message and exit. - **-, -l, --login**: Pretend the shell to be a login shell. - **-m, -p, --preserve-environment**: Preserve the entire environment. - **-s, --shell SHELL**: Use SHELL instead of the default `/system/bin/sh`. - **-v, --version**: Display version number and exit. - **-V**: Display version code and exit. - **-mm, -M, --mount-master**: Force run in the global mount namespace. ``` -------------------------------- ### Get Module Directory Path in Shell Scripts Source: https://github.com/topjohnwu/magisk/blob/master/docs/guides.md Use this command in all module scripts to reliably get the module's base directory path. Avoid hardcoding paths. ```shell MODDIR=${0%/*} ``` -------------------------------- ### Build System: Build Only Binaries or APK Source: https://context7.com/topjohnwu/magisk/llms.txt Build only the native binaries (magisk, magiskboot, magiskinit, magiskpolicy) using './build.py binary', or build only the Android application by navigating to the 'app' directory and running './gradlew assembleDebug'. ```bash # Build only native binaries (magisk, magiskboot, magiskinit, magiskpolicy) ./build.py binary # Build only the Android application cd app && ./gradlew assembleDebug ``` -------------------------------- ### Check Magisk Binary Version Source: https://github.com/topjohnwu/magisk/blob/master/docs/faq.md If the Magisk app shows 'Installed = N/A' after an update, you can check the installed Magisk binary version and version code using this command in a terminal emulator. ```bash magisk -c ``` -------------------------------- ### Abort Installation with Error Message in Magisk Source: https://github.com/topjohnwu/magisk/blob/master/docs/guides.md Use `abort` to display an error message and terminate the module installation. This function ensures cleanup steps are performed, unlike a direct 'exit'. ```sh abort ``` -------------------------------- ### Magisk CLI Source: https://github.com/topjohnwu/magisk/blob/master/docs/tools.md The `magisk` binary serves as a utility tool with various helper functions and entry points for Magisk services. It can be invoked with applets or options. ```APIDOC ## magisk ### Description The `magisk` binary acts as a versatile utility tool, providing access to helper functions and serving as the entry point for several Magisk services. It can be used with applets or directly with options. ### Usage ``` Usage: magisk [applet [arguments]...] or: magisk [options]... ``` ### Options - **-c** (`--current-version`): Print current binary version. - **-v** (`--daemon-version`): Print running daemon version. - **-V** (`--daemon-version-code`): Print running daemon version code. - **--list**: List all available applets. - **--remove-modules [-n]**: Remove all modules. Reboots if `-n` is not provided. - **--install-module ZIP**: Install a module from a ZIP file. ### Advanced Options (Internal APIs) - **--daemon**: Manually start the Magisk daemon. - **--stop**: Remove all Magisk changes and stop the daemon. - **--[init trigger]**: Callback on init triggers. Valid triggers: `post-fs-data`, `service`, `boot-complete`, `zygote-restart`. - **--unlock-blocks**: Set BLKROSET flag to OFF for all block devices. - **--restorecon**: Restore SELinux context on Magisk files. - **--clone-attr SRC DEST**: Clone permission, owner, and SELinux context from SRC to DEST. - **--clone SRC DEST**: Clone SRC to DEST. - **--sqlite SQL**: Execute SQL commands to the Magisk database. - **--path**: Print Magisk tmpfs mount path. - **--denylist ARGS**: Denylist configuration CLI. - **--preinit-device**: Resolve a device to store preinit files. ### Available Applets - `su` - `resetprop` ### Denylist Usage ``` Usage: magisk --denylist [action [arguments...] ] ``` #### Denylist Actions - **status**: Return the enforcement status. - **enable**: Enable denylist enforcement. - **disable**: Disable denylist enforcement. - **add PKG [PROC]**: Add a new target to the denylist. - **rm PKG [PROC]**: Remove target(s) from the denylist. - **ls**: Print the current denylist. - **exec CMDs...**: Execute commands in an isolated mount namespace and perform all unmounts. ``` -------------------------------- ### Magisk Module Structure Source: https://github.com/topjohnwu/magisk/blob/master/docs/guides.md Illustrates the required directory structure for a Magisk module, including essential files like module.prop and optional scripts. ```directory /data/adb/modules ├── . ├── . | ├── $MODID <--- The folder is named with the ID of the module │ │ │ │ *** Module Identity *** │ │ │ ├── module.prop <--- This file stores the metadata of the module │ │ │ │ *** Main Contents *** │ │ │ ├── system <--- This folder will be mounted if skip_mount does not exist │ │ ├── ... │ │ ├── ... │ │ └── ... │ │ │ ├── zygisk <--- This folder contains the module's Zygisk native libraries │ │ ├── arm64-v8a.so │ │ ├── armeabi-v7a.so │ │ ├── riscv64.so │ │ ├── x86.so │ │ ├── x86_64.so │ │ └── unloaded <--- If exists, the native libraries are incompatible │ │ │ │ *** Status Flags *** │ │ │ ├── skip_mount <--- If exists, Magisk will NOT mount your system folder │ ├── disable <--- If exists, the module will be disabled │ ├── remove <--- If exists, the module will be removed next reboot │ │ │ │ *** Optional Files *** │ │ │ ├── post-fs-data.sh <--- This script will be executed in post-fs-data │ ├── service.sh <--- This script will be executed in late_start service | ├── uninstall.sh <--- This script will be executed when Magisk removes your module | ├── action.sh <--- This script will be executed when user click the action button in Magisk app │ ├── system.prop <--- Properties in this file will be loaded as system properties by resetprop │ ├── sepolicy.rule <--- Additional custom sepolicy rules │ │ │ │ *** Auto Generated, DO NOT MANUALLY CREATE OR MODIFY *** │ │ │ ├── vendor <--- A symlink to $MODID/system/vendor │ ├── product <--- A symlink to $MODID/system/product │ ├── system_ext <--- A symlink to $MODID/system/system_ext │ │ │ │ *** Any additional files / folders are allowed *** │ │ │ ├── ... │ └── ... | ├── another_module │ ├── . │ └── . ├── . ├── . ``` -------------------------------- ### Get Magisk tmpfs Path Source: https://github.com/topjohnwu/magisk/blob/master/docs/details.md Use this command to retrieve the current base directory Magisk is using for temporary files. Binaries and symlinks are stored here. ```bash MAGISKTMP=$(magisk --path) ``` -------------------------------- ### Detect Magisk Environment with Info Object Source: https://context7.com/topjohnwu/magisk/llms.txt Initialize the Info object with a root shell to access device-level metadata. Check Magisk's active status, version, and device partition layout. Use version gating for feature compatibility. ```kotlin // Initialise from an open root Shell (called automatically in MagiskActivity) val shell = Shell.getShell() Info.init(shell) // Check whether Magisk is active and its version if (Info.env.isActive) { println("Magisk ${Info.env.versionString} (${Info.env.versionCode}) is running") } if (Info.env.isUnsupported) { println("Magisk version too old — please upgrade to ${Const.Version.MIN_VERSION}+") } // Device partition layout flags — determine correct installation target println("System-as-root : ${Info.isSAR}") println("A/B device : ${Info.isAB}") println("Boot ramdisk : ${Info.ramdisk}") println("Current slot : ${Info.slot}") // "_a" or "_b" println("Vendor boot : ${Info.isVendorBoot}") println("Legacy SAR : ${Info.legacySAR}") println("Zygisk enabled : ${Info.isZygiskEnabled}") println("Full-disk enc : ${Info.isFDE}") // Version gating for feature compatibility if (Const.Version.atLeast_28_0()) { println("DenyList enforcement when Zygisk disabled is supported") } if (Const.Version.atLeast_30_1()) { println("Linux capability restrictions in MagiskSU are supported") } // Fetch update information from GitHub/custom channel val networkService: NetworkService = ServiceLocator.networkService val update: UpdateInfo? = Info.fetchUpdate(networkService) update?.let { println("Latest stable : ${it.magisk.version} (${it.magisk.versionCode})") println("Download URL : ${it.magisk.link}") } ``` -------------------------------- ### MagiskSU (su) Command Usage Source: https://github.com/topjohnwu/magisk/blob/master/docs/tools.md The 'su' applet provides root access. Options include specifying a command to run, preserving environment variables, or forcing execution in the global mount namespace. ```bash Usage: su [options] [-] [user [argument...]] Options: -c, --command COMMAND Pass COMMAND to the invoked shell -g, --group GROUP Specify the primary group -G, --supp-group GROUP Specify a supplementary group. The first specified supplementary group is also used as a primary group if the option -g is not specified. -Z, --context CONTEXT Change SELinux context -t, --target PID PID to take mount namespace from -h, --help Display this help message and exit -, -l, --login Pretend the shell to be a login shell -m -p, --preserve-environment Preserve the entire environment -s, --shell SHELL Use SHELL instead of the default /system/bin/sh -v, --version Display version number and exit -V Display version code and exit -mm -M, --mount-master Force run in the global mount namespace ``` -------------------------------- ### Declare Folders to Replace in Magisk Module Source: https://github.com/topjohnwu/magisk/blob/master/docs/guides.md Use the REPLACE variable to specify directories that the module installer script should create a '.replace' file in. This indicates that these folders should be replaced. ```sh REPLACE=" /system/app/YouTube /system/app/Bloatware " ``` -------------------------------- ### Enable BusyBox Standalone Mode Source: https://github.com/topjohnwu/magisk/blob/master/docs/guides.md Demonstrates two methods to enable BusyBox's standalone mode for running scripts in a predictable environment. Method 1 is preferred as environment variables are inherited. ```shell ASH_STANDALONE=1 /data/adb/magisk/busybox sh