Skip to content

feat: install addons as Magisk modules when root is active#51

Merged
Shmayro merged 1 commit into
mainfrom
feat-magisk-modules-to-main
May 29, 2026
Merged

feat: install addons as Magisk modules when root is active#51
Shmayro merged 1 commit into
mainfrom
feat-magisk-modules-to-main

Conversation

@Shmayro
Copy link
Copy Markdown
Owner

@Shmayro Shmayro commented May 29, 2026

Re-targets the Magisk-module work from #49 onto main. #49 was originally stacked on #48 and got merged into the intermediate refactor/self-contained-installs branch instead of main — so its content never landed. Now that #50 (the refactor) is on main, this is the same commit cherry-picked unchanged on top.

Why

rootAVD only patches the ramdisk. The Magisk app's first-launch "additional setup" prompt is what normally populates /data/adb/magisk/ with the actual binaries (magisk64, magiskinit, magiskboot, magiskpolicy, busybox, stub.apk, …) — without that step, Magisk reports "environment incomplete, abort" on every boot and refuses to mount modules. That means modules dropped under /data/adb/modules/<id>/ are silently ignored.

Without this PR:

  • Addon files have to be pushed to /system directly, polluting the qcow2 system overlay.
  • Once Magisk is live, /system is wrapped in a read-only magic mount and any subsequent push-based install fails (the INSTALL_FAILED you'd hit if you flip a flag on an already-rooted container).
  • User has to open the Magisk app and tap "additional setup" before modules work.

Changes

install_root

  • adb root before any /data/adb/* write (the previous omission silently failed every write as the shell user).
  • After rootAVD.sh patches the ramdisk, reproduce the Magisk app's FixEnv: extract Magisk.zip's lib/x86_64/ and assets/, rename lib<name>.so<name> (same naming the Magisk updater-script does), drop app-only files (bootctl, main.jar, module_installer.sh, uninstaller.sh), chmod -R 755. /data/adb/magisk/ is then complete when the patched ramdisk activates on the next QEMU restart — no manual setup prompt.

install_gapps / install_arm_translation

  • New _magisk_module siblings to the existing _system paths. They write the payload under /data/adb/modules/<id>/system/ plus a module.prop.
  • For ARM specifically: a system.prop with the ABI / native-bridge properties (Magisk's resetprop overrides the ro.* first-write-wins rule) and a post-fs-data.sh that registers binfmt_misc (init.rc files injected via Magisk overlay aren't parsed by init).
  • Each branches on a tightened magisk_active() — now checks for the magiskinit binary, not just the directory, so the rootAVD-empty case correctly evaluates to "not yet ready".

Main flow ordering

  • install_root runs before install_gapps and install_arm_translation. When ROOT is enabled, the magisk-env is complete by the time the other two run, so they automatically take the module path.

Result

Verified end-to-end on a fresh AVD with ROOT_SETUP=GAPPS_SETUP=ARM_TRANSLATION=1:

  • /data/adb/magisk/ populated with magisk64, magiskinit, magiskboot, magiskpolicy, busybox, stub.apk, etc.
  • /data/adb/modules/ contains gapps/ and ndk_translation/
  • adb shell getprop ro.product.cpu.abilistx86_64,x86,arm64-v8a,armeabi-v7a,armeabi
  • adb shell ls /system/priv-app/ shows Google services (GoogleBackupTransport, GoogleExtServices, …) via Magisk's overlay
  • adb install v2rayNG_2.1.7_arm64-v8a.apk succeeds and the app launches cleanly (both com.v2ray.ang and com.v2ray.ang:bg processes alive, no SIGABRT in native_bridge_initialize)
  • No "Additional setup required" prompt when opening the Magisk app

Supersedes

When ROOT_SETUP is enabled, finish the Magisk install inline so the
addon installs land as proper Magisk modules instead of direct /system
pushes. Reproduces what the Magisk app does on first launch (the
"additional setup" prompt) without requiring a manual tap.

install_root now:
- Calls adb root first (the previous omission silently failed all
  writes into /data/adb/ as the shell user)
- After rootAVD patches the ramdisk, extracts Magisk.zip's lib/x86_64/
  and assets/ and stages them into /data/adb/magisk/, renaming
  lib<name>.so -> <name> and dropping bootctl/main.jar/installer scripts
  — same layout the Magisk updater-script produces

install_gapps and install_arm_translation gain a parallel
_magisk_module path that writes the payload under
/data/adb/modules/<id>/system/, plus a module.prop and (for ARM) a
system.prop with the ABI / native-bridge properties and a
post-fs-data.sh that registers binfmt_misc (init.rc files injected via
Magisk overlay aren't parsed by init).

magisk_active() checks for the magiskinit binary rather than just the
/data/adb/magisk directory, since the rootAVD-patched ramdisk creates
that directory empty and the old check returned a false positive.

The main flow now calls install_root before install_gapps and
install_arm_translation so the latter two see a populated Magisk env
and take the module path automatically.

Verified end-to-end on a fresh AVD with ROOT_SETUP=GAPPS_SETUP=
ARM_TRANSLATION=1: /data/adb/magisk/ ends up populated, modules
created under /data/adb/modules/{gapps,ndk_translation}, ABI list
advertises arm64-v8a,armeabi-v7a,armeabi, Google services visible at
/system/priv-app/ via Magisk's overlay, and an arm64-v8a-only APK
(v2rayNG) installs and launches.
@Shmayro Shmayro merged commit 4fc03ac into main May 29, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant