Skip to content

zygisk: make built-in Zygisk work on Meta Quest (lazy per-trust partition zygotes) - #9941

Closed
AbandonedAccount1111 wants to merge 1 commit into
topjohnwu:masterfrom
xAstroBoy:meta-quest-zygisk-fix
Closed

zygisk: make built-in Zygisk work on Meta Quest (lazy per-trust partition zygotes)#9941
AbandonedAccount1111 wants to merge 1 commit into
topjohnwu:masterfrom
xAstroBoy:meta-quest-zygisk-fix

Conversation

@AbandonedAccount1111

@AbandonedAccount1111 AbandonedAccount1111 commented Jul 7, 2026

Copy link
Copy Markdown

Superseded by #9968 (account migration).

…tion zygotes)

Meta Quest (Horizon OS) does not start the zygote the normal way: ro.zygote=
zygote64_stub32 launches /system/bin/stub_zygote, which forks a separate
app_process64 zygote PER security partition (system/trusted vs untrusted-app),
driven by hzos_security_zygote_partitioning_policy. The untrusted-app partition
zygote -- the one that forks 3rd-party apps and the Magisk manager -- is spawned
LAZILY, after boot-complete.

magiskd sets ro.dalvik.vm.native.bridge=libzygisk.so during boot but clears it
again at boot-complete (ZygiskState::reset). On a normal device every zygote has
already started by then, so clearing it is harmless. On Quest the untrusted-app
partition zygote reads the (now cleared) property when it finally execve's
app_process64, never loads libzygisk.so, so 3rd-party apps + the Magisk manager
are never injected -> "Zygisk: N/A".

Fix (daemon.rs): on the boot-complete reset(restore=true) path, reset the crash
counter but KEEP native.bridge set (set_prop) instead of clearing it
(restore_prop); only the >3-crash rollback path still clears. The lazily-spawned
partition zygotes then load the loader when they start.

Also (hook.cpp), robustness fixes the loader needs on this device:
 - Wrap hook_zygote_jni()'s JNI locals in PushLocalFrame(64)/PopLocalFrame so
   leaking locals can't trip ART's "non-empty local reference table" abort, and
   bail if GetEnv returns no env.
 - Make the strdup(ZygoteInit) trigger a substring match + add an idempotency
   guard so the zygote hooks install exactly once per process.

Verified on Quest 3 (Android 14): system_server + every app fork is intercepted
and LSPosed loads end-to-end.
@xAstroBoy
xAstroBoy force-pushed the meta-quest-zygisk-fix branch 2 times, most recently from 250199a to e64ff0c Compare July 22, 2026 13:04
@xAstroBoy

Copy link
Copy Markdown

Superseded by #9968 (account migration).

@dushane-smith

dushane-smith commented Jul 22, 2026 via email

Copy link
Copy Markdown

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.

3 participants