Plugin (Unrooted Module)
"Know your limits"
Background
The Plugin concept is built on the same architecture as root modules. It is not intended as a replacement, but rather as an additional feature that introduces an unrooted version within AxManager.
At this stage, the idea serves as an initial exploration: extending the root-module foundation into a form that can operate without root access, while still remaining part of the same modular framework.
In the future, this approach can be further developed to provide broader functionality and new use cases, balancing between rooted and unrooted environments.
WebUI
AxManager's plugins support displaying interfaces and interacting with users same as KernelSU but without root access. For more details, refer to the KernelSU WebUI documentation.
DIFFERENCE WITH KERNELSU
AxManager is support KernelSU API and only differs in permissions and how to treat local directories from webroot/index.html
BusyBox
AxManager ships with a feature-complete BusyBox binary (including full SELinux support). The executable is located at /data/data/local/tmp/AxManager/bin/busybox
, AxManager's BusyBox supports runtime toggle-able "ASH Standalone Shell Mode". What this Standalone Mode means is that when running in the ash shell of BusyBox, every single command will directly use the applet within BusyBox, regardless of what is set as PATH
. For example, commands like ls
, rm
, chmod
will NOT use what is in PATH (in the case of Android by default it will be /system/bin/ls
, /system/bin/rm
, and /system/bin/chmod
respectively), but will instead directly call internal BusyBox applets. This makes sure that scripts always run in a predictable environment and always have the full suite of commands no matter which Android version it is running on. To force a command not to use BusyBox, you have to call the executable with full paths.
Every single shell script running in the context of AxManager will be executed in BusyBox's ash
shell with Standalone Mode enabled. For what is relevant to 3rd party developers, this includes all boot scripts and module installation scripts.
DIFFERENCE WITH MAGISK / KERNELSU
AxManager's BusyBox is now using the binary file compiled directly from the Magisk project. Thanks to Magisk! Therefore, you don't need to worry about compatibility issues between BusyBox scripts in Magisk, KernelSU and AxManager, as they're exactly the same!
AxManager plugins
A AxManager plugins is a folder placed in /data/local/tmp/AxManager/plugins
with the structure below:
/data/local/tmp/AxManager/plugins
├── .
├── .
│
├── $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
│ │ └── bin <--- This folder will be added on PATH
│ │
│ │ *** Status Flags ***
│ │
│ ├── 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 BOOT_COMPLETED first sync
│ ├── service.sh <--- This script will be executed in BOOT_COMPLETED late_start service
│ ├── uninstall.sh <--- This script will be executed when AxManager removes your module
│ ├── action.sh <--- This script will be executed when user click the Action button in AxManager app
│ ├── system.prop <--- Properties in this file will be loaded as system properties by setprop (debug only)
│ │
│ │ *** Any additional files / folders are allowed ***
│ │
│ ├── ...
│ └── ...
│
├── another_module
│ ├── .
│ └── .
├── .
├── .
DIFFERENCE WITH ROOT METHOD
AxManager uses the BOOT_COMPLETED receiver and Hot Restart System approach to start post-fs-data.sh
, system.prop
, late_start service.sh
, and all other files are treated the same in root mode. except the root init method.
module.prop
module.prop is a configuration file for a module. In AxManager, if a module doesn't contain this file, it won't be recognized as a module. The format of this file is as follows:
id=<string>
name=<string>
version=<string>
versionCode=<int>
author=<string>
description=<string>
axeronPlugin=<int> <--- A field for targeting AxManager server version supported
id
has to match this regular expression:^[a-zA-Z][a-zA-Z0-9._-]+$
Example: ✓a_module
, ✓a.module
, ✓module-101
, ✗a module
, ✗1_module
, ✗-a-module
This is the unique identifier of your module. You should not change it once published.versionCode
has to be an integer. This is used to compare versions.- Others that were not mentioned above can be any single line string.
- Make sure to use the
UNIX (LF)
line break type and not theWindows (CR+LF)
orMacintosh (CR)
.
WARNING
Make sure the axeronPlugin=version
you are using is equal to or lower than your AxManager server version. If the server version is lower than axeronPlugin=version
, you won’t be able to flash it on AxManager.
Shell scripts
In all scripts of your module, please use MODDIR=${0%/*}
to get your module's base directory path EXCEPT customize.sh
; do NOT hardcode your module path in scripts.
DIFFERENCE WITH ROOT METHOD
You can use the environment variable AXERON
to determine if a script is running in AxManager, KernelSU or Magisk. If running in AxManager, this value will be set to true.
system
directory
DIFFERENCE WITH ROOT METHOD
AxManager for now only affects /system/bin
by adding it to the PATH
, so binaries there can be called directly in any script.
Plugin installer
A AxManager plugin installer is a root
module packaged in a ZIP file that can be flashed in the AxManager. The simplest AxManager plugin installer is just a root
module packed as a ZIP file.
module.zip
│
├── customize.sh <--- (Optional, more details later)
│
├── ...
├── ... /* The rest of module's files */
│
WARNING
KernelSU modules are NOT compatible for installation through custom Recovery.
AxManager plugins strictly follow the behavior of the underlying root
module being used.
Customize
If you need to customize the module installation process, optionally you can create a script in the installer named customize.sh
. This script will be sourced (not executed) by the module installer script after all files are extracted and default permissions and secontext are applied. This is very useful if your module requires additional setup based on the device ABI, or you need to set special permissions/secontext for some of your module files.
If you would like to fully control and customize the installation process, declare SKIPUNZIP=1
in customize.sh
to skip all default installation steps. By doing so, your customize.sh
will be responsible to install everything by itself.
The customize.sh script runs in AxManager's BusyBox ash shell with Standalone Mode enabled. The following variables and functions are available:
Variables
AXERON
(bool): a variable to mark that the script is running in the AxManager environment, and the value of this variable will always be true. You can use it to distinguish between AxManager, KernelSU and Magisk.AXERONVER
(int): the version int of currently running AxManager Server (e.g. 10400).BOOTMODE
(bool): always be true in AxManager.MODPATH
(path): the path where your module files should be installed.TMPDIR
(path): a place where you can temporarily store files.ZIPFILE
(path): your module's installation ZIP.ARCH
(string): the CPU architecture of the device. Value is either arm, arm64, x86, or x64.IS64BIT
(bool): true if $ARCH is either arm64 or x64.API
(int): the API level (Android version) of the device (e.g., 23 for Android 6.0).
Functions
ui_print <msg>
print <msg> to console
Avoid using 'echo' as it will not display in custom recovery's console
abort <msg>
print error message <msg> to console and terminate the installation
Avoid using 'exit' as it will skip the termination cleanup steps
set_perm <target> <owner> <group> <permission> [context]
if [context] is not set, the default is "u:object_r:system_file:s0"
this function is a shorthand for the following commands:
chown owner.group target
chmod permission target
chcon context target
set_perm_recursive <directory> <owner> <group> <dirpermission> <filepermission> [context]
if [context] is not set, the default is "u:object_r:system_file:s0"
for all files in <directory>, it will call:
set_perm file owner group filepermission context
for all directories in <directory> (including itself), it will call:
set_perm dir owner group dirpermission context