Repository navigation
Build the configuration before the binder an app attaches through - #1064
Closed
JingMatrix wants to merge 1 commit into
Closed
JingMatrix wants to merge 1 commit into
JingMatrix wants to merge 1 commit into
Conversation
`attachProcess` is answered inside the fork it is about. The Zygisk module transacts for its framework binder during specialization and the process does not continue until the reply arrives, so whatever the daemon does on that path, a starting application waits for. What it did there was build the whole configuration. `shouldSkipProcess` reaches the readiness latch, and the latch runs the rebuild under `rebuildLock`: every enabled module's APK parsed, its dexes read and rewritten, its scope expanded over every user with a package manager call apiece. The fork that got there first paid for all of it and every fork behind it waited on the same lock. Each of those processes is one AMS started, and AMS kills a process that has not attached within `PROC_START_TIMEOUT`, ten seconds — `failed to attach`, `start timeout`, reason 7 in `exit-info`, with nothing anywhere to say what it had been waiting for. A boot that starts fifteen processes inside that window loses fifteen of them. The rebuild moves to the one point where it costs nobody anything: `main`, after the four core services it needs are up and before `sendToBridge` publishes the binder an injected process looks us up through. Nothing can attach until that call returns, and once the latch is closed `attachProcess` never takes the lock again. It runs on the main thread, which already blocks there — `sendToBridge` waits on `activity` in a loop of its own — and `system_server`'s own handshake arrives on a binder thread through the proxy name claimed at the very top of `main`, so it is unaffected either way. Also here: the latch is set only if a rebuild actually published a state. It used to be set whatever happened, so a rebuild that bailed because the user service had not answered — which it refuses to read as "no module is installed", correctly — left an empty module set marked as the finished one: every process skipped for the life of the daemon, while the framework reported itself as up. Both reasons a rebuild bails are cheap to re-reach, so the next caller simply tries again. Fixes #1050
1 task done
Owner
Author
|
Low quality AI PR, didn't even check if the issue writer is using Vector at all. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
attachProcessis answered inside the fork it is about.RequestAppBindertransacts for the framework binder during specialization, synchronously and with no flags, so whatever the daemon does on that path a starting application waits for.What it did there was build the whole configuration.
shouldSkipProcessreaches the readiness latch, and the latch runsperformCacheUpdateunderrebuildLock: every enabled module's APK parsed, its dexes read and rewritten through the slicer, its scope expanded over every user with a package manager call apiece. The first fork to arrive paid for all of it and every fork behind it waited on the same lock. Each of those processes is one AMS started, and AMS kills a process that has not attached withinPROC_START_TIMEOUT, ten seconds —failed to attach,start timeout, reason 7 indumpsys activity exit-info. #1050 reports fifteen or sixteen of them on every boot, each killed exactly 10.0 s after itsStart proc, and none on a boot with the module disabled.The rebuild moves to the one point where it costs nobody anything:
main, after the four core services it needs are up and beforesendToBridgepublishes the binder an injected process looks us up through. Nothing can attach until that call returns, and once the latch is closedattachProcessnever takes the lock again — the fast path is a volatile read. It runs on the main thread, which already blocks there, sincesendToBridgewaits onactivityin a loop of its own, andsystem_server's own handshake arrives on a binder thread through the proxy name claimed at the very top ofmain, so that is unaffected either way.Also here: the latch is set only if a rebuild actually published a state. It used to be set whatever happened, so a rebuild that bailed because the user service had not answered — which it refuses to read as "no module is installed", correctly, and which is likelier now that the first attempt is earlier — left an empty module set marked as the finished one: every process skipped for the life of the daemon while the framework reported itself as up. Both reasons a rebuild bails are reached before any of the expensive work, so retrying costs nothing and the next caller simply does.
Left alone: the lock itself, and the rebuild's cost. Serialising rebuilds is right, and a package install still pays for one; what changes is that no fork is behind it. Also left alone: the processes forked between the zygote starting and
sendToBridgereturning, which get no injection. That window already existed and this adds the rebuild to it — a few hundred milliseconds of it, on a path where the alternative was a process AMS kills.Not tested on a device. #1050's measurement is against LSPosed 7912 rather than this daemon, so the numbers there are evidence for the shape and not for the fix.