You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
No injection after a KernelSU emulated soft reboot spawns a duplicate daemon #878
changed the title [-]The latest version (v2.2-3080-88f8e1fa) cannot be injected in the HyperOS (Redmi K80 Pro) + Zygisk Next environment; both the parasite manager and Hook functions are disabled (v2.1 works normally).[/-][+] No injection under exploit-gained KernelSU jailbreak root[/+]on Aug 6, 2026
I tried reinstalling the latest version of Vector and performing a soft reboot four times to reproduce the original problem. Each of these four tests yielded different results. The first two times, Vector crashed and failed to inject into the system framework. The third time, the DEX optimizer wrapper failed to mount. The fourth time, the problem reappeared after the reboot; Vector could not be opened. The logs should contain most of the logs from my tests from this morning to this afternoon.
Let us enable only (Neo)Zygisk and Vector, do a full reboot, trigger Vector Action button, and then upload the whole folder /data/adb/lspd/log as logs (you have pack it in .zip by your own.)
Let us enable only (Neo)Zygisk and Vector, do a full reboot, trigger Vector Action button, and then upload the whole folder /data/adb/lspd/log as logs (you have pack it in .zip by your own.)
I understand, but I can only perform the following steps:
Uninstall the existing Vector
Perform a hardware reboot
Re-execute the vulnerability to jailbreak
Install Vector
Perform a soft reboot to make Vector effective
If I don't do this, a hardware reboot will cause the KSU jailbreak to disappear.
Can this solution find the problem?
Yes, please do as you suggest. And remember to pack the logs for uploading.
I have followed the procedure. The current situation is:
After a hardware reboot, reinstalling Vector and Vector runs normally.
However, a subsequent soft reboot causes the aforementioned problem.
The logs are attached; they should contain details of my two reboot attempts. The first reboot was normal, but the subsequent soft reboot caused the problem.
changed the title [-] No injection under exploit-gained KernelSU jailbreak root[/-][+]No injection after a KernelSU emulated soft reboot spawns a duplicate daemon[/+]on Aug 6, 2026
Thanks, these logs are exactly what was needed. Root cause is clear now.
The trigger is KernelSU's emulated soft reboot. It doesn't reboot the kernel — it runs stop, replays post-fs-data and services, then start. That tears down and respawns zygote (which is why NeoZygisk re-injects correctly), but it also re-runs every module's service.sh, including Vector's. The existing Vector daemon is a detached process, so stop doesn't kill it, and it has no idea a second service.sh was just fired. The result is two daemons: the survivor from the previous boot and a fresh one. Both claim the same rendezvous service, forward transactions to each other, and one crashes on a stack overflow. No framework gets injected, so the manager opens into the shell warning.
This also matches what you saw: the first soft reboot after installing works because there's no prior daemon; every soft reboot after that collides with the one already running.
It is hard to find a solution, you will have to wait.
Currently, the only workaround for you, is to avoid soft-reboot from KernelSU
Why did some previous versions seem to have no problem? But overall, the issue isn't serious. Now that we know the cause, we can use the following temporary solution: disable vector in ksu, then perform a soft reboot, and then enable vector again and perform another soft reboot. This only requires an extra soft reboot.
@RMDycz If you have some working version, please share the link and the logs generated by that build, it will help us to solve this in new versions of Vector.
@RMDycz If you have some working version, please share the link and the logs generated by that build, it will help us to solve this in new versions of Vector.
Okay, the Vector v2.1 (3076-1e595f3c-HSSkyBoy) version I mentioned before also has the same problem. However, I can confirm that Vector 2.0 Mar 23 version does not have this issue because I have been using this version for a considerable period of time.
@RMDycz If you have some working version, please share the link and the logs generated by that build, it will help us to solve this in new versions of Vector.
This could also be an issue with the KSU update, because the KSU version I was using before was an older one, probably the May version of Vector and the May version of KSU. It might take some time to test the versions to find out exactly where the problem lies.
@astr64 Thanks — worth separating, because two failures in this thread look identical from the UI and the kill only covers one.
One thing ruled out first: the ksud that Root-My-Pixel ships (app/src/main/assets/ksud/ksud-android15-6.6, sha256 cdc8f210…) contains the emulated-soft-reboot stage, and ReSukiSU's soft_reboot() and run_stage() are line-for-line the same as upstream's, including the on_services() call that re-runs service.sh. So on your setup the stage exists and so does the bug — the difference is not the version.
Duplicate daemon, script absent, fresh boot, three consecutive soft reboots:
cycle
vectord pid
injected
failed to inject
1
10020
yes
—
2
10020
yes
yes
3
10020
no
yes
The pid is frozen across all three; cycle 1 is clean only because there is no survivor yet. With the script, seven cycles across two boots: one daemon each, injected each, pid changing every cycle instead of freezing.
A false negative worth ruling out: my first check logged the marker to /dev/kmsg and read back nothing, because the soft reboot's own message burst rotates the ring buffer within seconds. I nearly concluded the stage never runs. A file showed it running normally.
Three things that separate the cases:
echo "$(date) [$(pgrep -f '^vectord')]" >> /data/local/tmp/esr-trace.log as the script's first line, soft reboot, then cat it. Empty = the stage never ran and the kill is still untested.
pgrep -f '^vectord' while Vector is healthy. Empty = the pattern does not match on your build, so the script is a no-op even when it runs.
If the trace is empty, check the ksud log for Magisk detected, skip or safe mode, skip — run_stage returns early on either and only logs a warning.
If the trace shows the kill happening and injection still fails with a single daemon and no StackOverflowError, that is a different failure from this one and worth its own logs — the daemon comes up before system_server on every cycle and the wait loop normally handles it, so the interesting question there is what the servicemanager lookup returned.
Limits: seven cycles with the script, four without, across three boots on one device and one SoC. No Pixel data.
@astr64 Thanks — worth separating, because two failures in this thread look identical from the UI and the kill only covers one.
One thing ruled out first: the ksud that Root-My-Pixel ships (app/src/main/assets/ksud/ksud-android15-6.6, sha256 cdc8f210…) contains the emulated-soft-reboot stage, and ReSukiSU's soft_reboot() and run_stage() are line-for-line the same as upstream's, including the on_services() call that re-runs service.sh. So on your setup the stage exists and so does the bug — the difference is not the version.
Hallucinated AI Babble goes on
I don't understand the point of a blind troubleshooting AI frenzy. It ultimately does nothing right. We all have access to LLMs and can burn tokens until we get to a working product.
Based on our discussion, I made a KSU module as a temporary workaround until PR #914 is merged, for those who want to use Vector with a late-loaded KSU. It uses the emulated-soft-reboot hook to kill the previous vectord process whenever a soft reboot is performed.
After a soft reboot, the global dex2oat bind mount remains in place. The new vectord then treats the already-wrapped path as the stock dex2oat, so once dexopt is triggered, the wrapper ends up recursively execing itself.
Based on our discussion, I made a KSU module as a temporary workaround until PR #914 is merged, for those who want to use Vector with a late-loaded KSU. It uses the emulated-soft-reboot hook to kill the previous vectord process whenever a soft reboot is performed.
Based on our discussion, I made a KSU module as a temporary workaround until PR #914 is merged, for those who want to use Vector with a late-loaded KSU. It uses the emulated-soft-reboot hook to kill the previous vectord process whenever a soft reboot is performed. vector-soft-reboot-guard-v0.1.0.zip
I rebuilt vector with 914 applied, and it didn't work for me. Any info can provide? (Pixel 10, Root My Pixel)
I think the implementation in #914 is still not quite correct. As I mentioned above, stale dex2oat bind mounts can still remain after a soft reboot.
I've added some additional cleanup logic to the KSU module. You can use an official Vector build without #914 together with this updated module to verify whether the issue is fixed.
Note: The first soft reboot after installing this module only activates it. You'll need to perform one more soft reboot to clean up the stale state and verify whether vectord restarts normally.
I think the implementation in #914 is still not quite correct. As I mentioned above, stale dex2oat bind mounts can still remain after a soft reboot.
I've added some additional cleanup logic to the KSU module. You can use an official Vector build without #914 together with this updated module to verify whether the issue is fixed.
Note: The first soft reboot after installing this module only activates it. You'll need to perform one more soft reboot to clean up the stale state and verify whether vectord restarts normally.
Hi! I used the soft reboot guard you've attached, but sadly it doesn't really do anything
@H3XDaemon your solution works fine on samsung, i had to include small change., after soft reboot trying to install any app causes system crash.
1789994679.653 artd 980 980 W LSPlt : symbol _ZNK3art9OatHeader16GetKeyValueStoreEv not found in PLT table
1789994679.643 artd 980 980 W LSPlt : symbol _ZNK3art9OatHeader16GetKeyValueStoreEv not found in PLT table
1789994679.634 artd 980 980 W LSPlt : symbol _ZNK3art9OatHeader16GetKeyValueStoreEv not found in PLT table
setenforce 0 , makes vectord to umount dex2oat [https://github.com/JingMatrix/Vector/blob/master/daemon/src/main/kotlin/org/matrix/vector/daemon/env/Dex2OatServer.kt#L86] , fixing the crash
emulated-soft-reboot.sh
pids=$(pgrep -f '^vectord')
if [ -n "$pids" ]; then
setenforce 0
sleep 1
kill -9 $pids
setenforce 1
fi
I opened #1012, building on H3XDaemon's pre-stop hook and ManiaciaChao's stale compiler-mount diagnosis. It handles both the surviving daemon and its mounts, including first-update post-fs-data cleanup, without relying on the process name or toggling SELinux.
It includes the complete script-level lifecycle change, applies directly to master, and does not depend on #914 or #1008. It overlaps #914; the separate compiler recursion guards from #1008 are not included.
It includes 24 Linux integration tests (passing with dash, BusyBox and mksh). The same four production scripts were observed through one successful Android 12 cycle; validation details and limits are in the PR.
The stage does run here — our emulated-soft-reboot.sh writes a line to a file, and the timestamps line up with a real ksud soft-reboot. (/dev/kmsg is useless for this: the soft reboot's own burst rotates the ring buffer within seconds.)
Three things I did not see above:
KernelSU applies module mounts once per load, not per soft reboot. A module installed while late-loaded is not mounted by a later ksud soft-reboot: the scripts are replayed, the overlay is not re-created. We watched this with a module of ours that ships a permission XML and an overlay library — after ksud post-fs-data (and after a soft reboot) the files were still absent from /system, /proc/1/mountinfo had no matching entry, and that module's own post-fs-data.sh had clearly run. So the "the first soft reboot after installing only activates it" note above is not a quirk of that particular module — it is how the mount stage behaves. Anything that has to be live sooner must be brought in by hand (mount --bind), which is how we ended up testing it.
On this firmware ksud soft-reboot is not a safe way to get Vector back up, even with the duplicate handled. Our last attempt had system_server come up before the APEX-provided android.ext.services package was resolvable (Required services extension package is missing ... android.ext.services), crash-loop, and Rescue Party reboot the device — losing root, since a late-loaded LKM does not survive a real reboot. What we do instead: start vectord first (it claims the serial proxy name early), then start Zygisk Next and let its zygote restart hand the new system_server to the waiting daemon. That is KernelSU-side rather than Vector-side, but it is why "just avoid the soft reboot" is a cheap workaround on a normal device and an expensive one here.
A three-line guard for the case where the KernelSU stage does not exist (Magisk, APatch) or does not run. Starting a second daemon is what creates the collision, and service.sh can notice that one is already alive: if pgrep -f '^vectord' >/dev/null 2>&1; then exit 0; fi. Anchored, because app_process sets the nice name in argv only — comm stays main, so pkill vectord matches nothing, while an unanchored pattern matches any shell whose command line happens to contain the word.
What a daemon restart leaves behind when system_server is already running — a permanently false "not injected" state with no repair path — is filed separately: #1015.
I opened #1017 for the daemon-restart gap described here and in #1015. It re-registers an already injected system_server through the existing bridge, restores loaded modern modules’ IPC/preferences and hot-reload targets, and derives manager status from the live registration. It does not rerun module entry points or reinstall hooks. Native startup also waits for a successful registration handshake rather than accepting an unrelated binder at the proxy name.
This complements #1012’s daemon/compiler-mount cleanup and applies directly to master. #1018 separately releases consumed hot-reload resources and retired callbacks. The three changes also compile and pass their regression suites together.
An Android 12/NeoZygisk local validation build passed daemon replacements with unchanged system_server/zygote PID and start times, then a KernelSU emulated soft reboot followed by application and hot-reload tests. Clean PR sources were compiled separately. I have not reproduced the locked-bootloader LKM setup; these changes do not restore external overlays or fix the reported APEX/extension-package failure.
Activity
JingMatrix commentedon Aug 6, 2026
Please upload the log folder as indicated in #123.
[-]The latest version (v2.2-3080-88f8e1fa) cannot be injected in the HyperOS (Redmi K80 Pro) + Zygisk Next environment; both the parasite manager and Hook functions are disabled (v2.1 works normally).[/-][+] No injection under exploit-gained KernelSU jailbreak root[/+]RMDycz commentedon Aug 6, 2026
@JingMatrix
JingMatrix commentedon Aug 6, 2026
Let us enable only (Neo)Zygisk and Vector, do a full reboot, trigger Vector Action button, and then upload the whole folder
/data/adb/lspd/logas logs (you have pack it in.zipby your own.)RMDycz commentedon Aug 6, 2026
I understand, but I can only perform the following steps:
Uninstall the existing Vector
Perform a hardware reboot
Re-execute the vulnerability to jailbreak
Install Vector
Perform a soft reboot to make Vector effective
If I don't do this, a hardware reboot will cause the KSU jailbreak to disappear.
Can this solution find the problem?
JingMatrix commentedon Aug 6, 2026
Yes, please do as you suggest. And remember to pack the logs for uploading.
RMDycz commentedon Aug 6, 2026
I have followed the procedure. The current situation is:
After a hardware reboot, reinstalling Vector and Vector runs normally.
However, a subsequent soft reboot causes the aforementioned problem.
The logs are attached; they should contain details of my two reboot attempts. The first reboot was normal, but the subsequent soft reboot caused the problem.
vector_logs.zip
[-] No injection under exploit-gained KernelSU jailbreak root[/-][+]No injection after a KernelSU emulated soft reboot spawns a duplicate daemon[/+]JingMatrix commentedon Aug 6, 2026
Thanks, these logs are exactly what was needed. Root cause is clear now.
The trigger is KernelSU's emulated soft reboot. It doesn't reboot the kernel — it runs
stop, replayspost-fs-dataandservices, thenstart. That tears down and respawns zygote (which is why NeoZygisk re-injects correctly), but it also re-runs every module'sservice.sh, including Vector's. The existing Vector daemon is a detached process, sostopdoesn't kill it, and it has no idea a secondservice.shwas just fired. The result is two daemons: the survivor from the previous boot and a fresh one. Both claim the same rendezvous service, forward transactions to each other, and one crashes on a stack overflow. No framework gets injected, so the manager opens into the shell warning.This also matches what you saw: the first soft reboot after installing works because there's no prior daemon; every soft reboot after that collides with the one already running.
JingMatrix commentedon Aug 6, 2026
It is hard to find a solution, you will have to wait.
Currently, the only workaround for you, is to avoid soft-reboot from KernelSU
RMDycz commentedon Aug 7, 2026
Why did some previous versions seem to have no problem? But overall, the issue isn't serious. Now that we know the cause, we can use the following temporary solution: disable vector in ksu, then perform a soft reboot, and then enable vector again and perform another soft reboot. This only requires an extra soft reboot.
JingMatrix commentedon Aug 7, 2026
@RMDycz If you have some working version, please share the link and the logs generated by that build, it will help us to solve this in new versions of Vector.
RMDycz commentedon Aug 7, 2026
Okay, the Vector v2.1 (3076-1e595f3c-HSSkyBoy) version I mentioned before also has the same problem. However, I can confirm that Vector 2.0 Mar 23 version does not have this issue because I have been using this version for a considerable period of time.
RMDycz commentedon Aug 10, 2026
This could also be an issue with the KSU update, because the KSU version I was using before was an older one, probably the May version of Vector and the May version of KSU. It might take some time to test the versions to find out exactly where the problem lies.
1 remaining item
astr64 commentedon Aug 13, 2026
I can confirm @H3XDaemon 's solution does not work on Pixel devices running rootmypixel.
I still experience identical issues.
H3XDaemon commentedon Aug 13, 2026
@astr64 Thanks — worth separating, because two failures in this thread look identical from the UI and the kill only covers one.
One thing ruled out first: the ksud that Root-My-Pixel ships (
app/src/main/assets/ksud/ksud-android15-6.6, sha256cdc8f210…) contains theemulated-soft-rebootstage, and ReSukiSU'ssoft_reboot()andrun_stage()are line-for-line the same as upstream's, including theon_services()call that re-runsservice.sh. So on your setup the stage exists and so does the bug — the difference is not the version.Duplicate daemon, script absent, fresh boot, three consecutive soft reboots:
The pid is frozen across all three; cycle 1 is clean only because there is no survivor yet. With the script, seven cycles across two boots: one daemon each, injected each, pid changing every cycle instead of freezing.
A false negative worth ruling out: my first check logged the marker to
/dev/kmsgand read back nothing, because the soft reboot's own message burst rotates the ring buffer within seconds. I nearly concluded the stage never runs. A file showed it running normally.Three things that separate the cases:
echo "$(date) [$(pgrep -f '^vectord')]" >> /data/local/tmp/esr-trace.logas the script's first line, soft reboot, thencatit. Empty = the stage never ran and the kill is still untested.pgrep -f '^vectord'while Vector is healthy. Empty = the pattern does not match on your build, so the script is a no-op even when it runs.Magisk detected, skiporsafe mode, skip—run_stagereturns early on either and only logs a warning.If the trace shows the kill happening and injection still fails with a single daemon and no
StackOverflowError, that is a different failure from this one and worth its own logs — the daemon comes up before system_server on every cycle and the wait loop normally handles it, so the interesting question there is what the servicemanager lookup returned.Limits: seven cycles with the script, four without, across three boots on one device and one SoC. No Pixel data.
astr64 commentedon Aug 13, 2026
I don't understand the point of a blind troubleshooting AI frenzy. It ultimately does nothing right. We all have access to LLMs and can burn tokens until we get to a working product.
JingMatrix commentedon Aug 13, 2026
@astr64 I will review the PR once it iterates till a mature stage.
No worries, quality of merged code is always guaranteed.
astr64 commentedon Aug 13, 2026
@JingMatrix What sort of logs can I provide to benefit development and fixing this bug?
I enter a double soft loop with basically any version of Vector (tried 2.0, 2.1, 2.2, and the latest 2.2 betas)
JingMatrix commentedon Aug 13, 2026
@astr64 I have not an implementation plan yet, let us be patient. I am currently busy with
TEESimulator.The support is broken now for sure. I will ask for your test once I start to inspect a solution. Thanks
astr64 commentedon Aug 13, 2026
Thank you for your service and work on TEE, and hit me up when you tackle this issue! Godspeed
ManiaciaChao commentedon Aug 24, 2026
Based on our discussion, I made a KSU module as a temporary workaround until PR #914 is merged, for those who want to use Vector with a late-loaded KSU. It uses the
emulated-soft-reboothook to kill the previousvectordprocess whenever a soft reboot is performed.vector-soft-reboot-guard-v0.1.0.zipIt still has a problem:
astr64 commentedon Aug 24, 2026
I rebuilt vector with 914 applied, and it didn't work for me. Any info can provide? (Pixel 10, Root My Pixel)
ManiaciaChao commentedon Aug 24, 2026
I think the implementation in #914 is still not quite correct. As I mentioned above, stale dex2oat bind mounts can still remain after a soft reboot.
I've added some additional cleanup logic to the KSU module. You can use an official Vector build without #914 together with this updated module to verify whether the issue is fixed.
vector-soft-reboot-guard-v0.2.0.zip
Note: The first soft reboot after installing this module only activates it. You'll need to perform one more soft reboot to clean up the stale state and verify whether
vectordrestarts normally.ezariago commentedon Sep 9, 2026
Hi! I used the soft reboot guard you've attached, but sadly it doesn't really do anything
grischuk-c commentedon Sep 21, 2026
@H3XDaemon your solution works fine on samsung, i had to include small change., after soft reboot trying to install any app causes system crash.
1789994679.653 artd 980 980 W LSPlt : symbol _ZNK3art9OatHeader16GetKeyValueStoreEv not found in PLT table
1789994679.643 artd 980 980 W LSPlt : symbol _ZNK3art9OatHeader16GetKeyValueStoreEv not found in PLT table
1789994679.634 artd 980 980 W LSPlt : symbol _ZNK3art9OatHeader16GetKeyValueStoreEv not found in PLT table
setenforce 0 , makes vectord to umount dex2oat [https://github.com/JingMatrix/Vector/blob/master/daemon/src/main/kotlin/org/matrix/vector/daemon/env/Dex2OatServer.kt#L86] , fixing the crash
emulated-soft-reboot.sh
pids=$(pgrep -f '^vectord')
if [ -n "$pids" ]; then
setenforce 0
sleep 1
kill -9 $pids
setenforce 1
fi
exit 0
Edit:- i think we can directly call umount
bartasc4 commentedon Oct 17, 2026
I opened #1012, building on H3XDaemon's pre-stop hook and ManiaciaChao's stale compiler-mount diagnosis. It handles both the surviving daemon and its mounts, including first-update
post-fs-datacleanup, without relying on the process name or toggling SELinux.It includes the complete script-level lifecycle change, applies directly to master, and does not depend on #914 or #1008. It overlaps #914; the separate compiler recursion guards from #1008 are not included.
It includes 24 Linux integration tests (passing with dash, BusyBox and mksh). The same four production scripts were observed through one successful Android 12 cycle; validation details and limits are in the PR.
kinghe2023 commentedon Oct 18, 2026
Confirming this on a second device, plus one KernelSU behaviour worth knowing while testing the hooks above.
Device: Samsung Galaxy S25 (SM-S931U1), Android 16 / One UI 8, KernelSU v3.2.5 LKM late-load (locked bootloader), Vector v2.2 (3080), Zygisk Next 1.5.2.
The stage does run here — our
emulated-soft-reboot.shwrites a line to a file, and the timestamps line up with a realksud soft-reboot. (/dev/kmsgis useless for this: the soft reboot's own burst rotates the ring buffer within seconds.)Three things I did not see above:
KernelSU applies module mounts once per load, not per soft reboot. A module installed while late-loaded is not mounted by a later
ksud soft-reboot: the scripts are replayed, the overlay is not re-created. We watched this with a module of ours that ships a permission XML and an overlay library — afterksud post-fs-data(and after a soft reboot) the files were still absent from/system,/proc/1/mountinfohad no matching entry, and that module's ownpost-fs-data.shhad clearly run. So the "the first soft reboot after installing only activates it" note above is not a quirk of that particular module — it is how the mount stage behaves. Anything that has to be live sooner must be brought in by hand (mount --bind), which is how we ended up testing it.On this firmware
ksud soft-rebootis not a safe way to get Vector back up, even with the duplicate handled. Our last attempt had system_server come up before the APEX-providedandroid.ext.servicespackage was resolvable (Required services extension package is missing ... android.ext.services), crash-loop, and Rescue Party reboot the device — losing root, since a late-loaded LKM does not survive a real reboot. What we do instead: startvectordfirst (it claims theserialproxy name early), then start Zygisk Next and let its zygote restart hand the new system_server to the waiting daemon. That is KernelSU-side rather than Vector-side, but it is why "just avoid the soft reboot" is a cheap workaround on a normal device and an expensive one here.A three-line guard for the case where the KernelSU stage does not exist (Magisk, APatch) or does not run. Starting a second daemon is what creates the collision, and
service.shcan notice that one is already alive:if pgrep -f '^vectord' >/dev/null 2>&1; then exit 0; fi. Anchored, becauseapp_processsets the nice name inargvonly —commstaysmain, sopkill vectordmatches nothing, while an unanchored pattern matches any shell whose command line happens to contain the word.What a daemon restart leaves behind when system_server is already running — a permanently false "not injected" state with no repair path — is filed separately: #1015.
bartasc4 commentedon Oct 18, 2026
I opened #1017 for the daemon-restart gap described here and in #1015. It re-registers an already injected
system_serverthrough the existing bridge, restores loaded modern modules’ IPC/preferences and hot-reload targets, and derives manager status from the live registration. It does not rerun module entry points or reinstall hooks. Native startup also waits for a successful registration handshake rather than accepting an unrelated binder at the proxy name.This complements #1012’s daemon/compiler-mount cleanup and applies directly to master. #1018 separately releases consumed hot-reload resources and retired callbacks. The three changes also compile and pass their regression suites together.
An Android 12/NeoZygisk local validation build passed daemon replacements with unchanged
system_server/zygote PID and start times, then a KernelSU emulated soft reboot followed by application and hot-reload tests. Clean PR sources were compiled separately. I have not reproduced the locked-bootloader LKM setup; these changes do not restore external overlays or fix the reported APEX/extension-package failure.