Skip to content

Stop the LSPosed hooks' debug flag from depending on inotify - #317

Merged
okhsunrog merged 1 commit into
mainfrom
fix/hook-debug-flag-stale
Aug 26, 2026
Merged

Stop the LSPosed hooks' debug flag from depending on inotify#317
okhsunrog merged 1 commit into
mainfrom
fix/hook-debug-flag-stale

Conversation

@okhsunrog

Copy link
Copy Markdown
Owner

Found while investigating an unrelated report on a live Pixel 8 Pro: system_server was writing VpnHide-NC/VpnHide-NI lines — the ones that name the exact UIDs we hook — at roughly 3/s, five days after Debug logging had been switched off. The canonical config on disk said debug: false and had said so since the day after that boot.

HookLog.enabled was assigned in exactly one place, HookLog.reload(), reachable only from install() at boot and from the FileObserver callback. That observer had stopped delivering — an atomic rename over the config produced no callback at all, confirmed on the device — so the flag was frozen at its boot value and no amount of toggling in the app could move it. Only a reboot could.

SystemServerConfigCache sits right beside it re-reading the same file every second by fingerprint, and was current the whole time: the hooks' targeting was correct, only the logging flag was stale. So the flag now belongs to the component that already polls.

  • SystemServerConfigCache sets HookLog.enabled whenever it installs a freshly-read config
  • HookLog.install() primes through that same path; reload() is gone
  • the watcher stays as a latency optimisation, with comments saying correctness must not hang off it

Not a leak — nothing an app can read. It is a toggle that silently did nothing, plus a stream of log calls on a Binder hot path that the user had asked us to stop making.

Testing: the stale-flag state was reproduced and confirmed on hardware (atomic rename over the config produced no observer callback while the cache stayed current). End-to-end verification of the fix needs the module reloaded into system_server, i.e. a reboot on a test device.

Found on a live Pixel 8 Pro: system_server was writing VpnHide-NC/NI lines to
logcat — the ones that name the exact UIDs we hook — at ~3/s, five days after
Debug logging had been turned off. The canonical config on disk said
debug:false and had said so since the day after that boot.

HookLog.enabled was assigned in exactly one place, HookLog.reload(), reachable
only from install() at boot and from the FileObserver callback. That observer
had stopped delivering: an atomic rename over the config produced no callback at
all, confirmed on the device. So the flag was frozen at whatever the config said
at boot, and no amount of toggling in the app could move it — only a reboot.

The irony is that SystemServerConfigCache sits right beside it re-reading the
same file every second by fingerprint, and was current the whole time. The
hooks' targeting was right; only the logging flag was stale. So give the flag to
the component that already polls: the cache sets HookLog.enabled whenever it
installs a fresh config. The watcher stays, as latency rather than correctness —
it makes a flip land immediately instead of within a second — and the comments
now say so, because the next person to add state here will be tempted to hang it
off the same callback.

Not a leak: nothing an app can read. It is a toggle that silently did nothing,
plus a stream of Binder-hot-path log calls the user asked us to stop making.
@okhsunrog
okhsunrog merged commit 0067f99 into main Aug 26, 2026
35 checks passed
@okhsunrog
okhsunrog deleted the fix/hook-debug-flag-stale branch August 26, 2026 09:13
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