Skip to content

Fix the scope requests that cannot be granted and the answers that are dropped - #890

Merged
JingMatrix merged 1 commit into
masterfrom
scope-request-answers
Aug 7, 2026
Merged

Fix the scope requests that cannot be granted and the answers that are dropped#890
JingMatrix merged 1 commit into
masterfrom
scope-request-answers

Conversation

@JingMatrix

Copy link
Copy Markdown
Owner

"system" is the framework rather than a package: it names system_server, which belongs to no package and resolves for nobody. dispatchModuleScope looked the requested package up before acting on the button, so every framework prompt died at that lookup — the approval the user had just given was answered "Package not found", the request was closed, its notification cancelled and no row written. The approve branch normalises "system" to user 0, and that line could never once have run. The framework name is now accepted without asking the package manager, and the lookup moved under "approve", the only answer that has to name something real: deny and the one-hour timeout were reported as "Package not found" as well when a package had been uninstalled while the prompt was up, which told the module the opposite of what had happened.

One request is now one prompt. IXposedService.requestScope takes a list and a single IXposedScopeCallback for it, and OnScopeEventListener is documented to run "when the request is completed", but ModuleAppService fanned the list out into one prompt per package and each was answered in its own right — a module asking for three packages made the user answer three questions and then fired that one listener three times, and a module that took the first answer as the answer acted on a third of it. NotificationManager.withdrawScopeRequests already carried a note about that cost. The whole list now goes up as one prompt whose Approve answers for all of it, deduplicated and sorted so that the same set asked twice replaces its own prompt rather than stacking a second copy of the same question, and MAX_OPEN_SCOPE_REQUESTS_PER_MODULE bounds calls rather than packages. What the user gives away in one press is what the prompt lists, so it lists all of them.

An approval was thrown away when the module's process had died. A prompt sits for an hour and the app a module runs inside can be killed at any point in it, and the receiver returned on !callbackBinder.isBinderAlive above both the claim and the cancel: the user pressed Approve, nothing was written, and the prompt stayed on screen with live buttons that did nothing for the rest of the hour. An approval is a decision about the module's scope and is recorded whether or not the module is still there to be told; deny and the timeout still take the prompt down; and the one call that can fail against a dead module is caught where it is made. setModuleScope is skipped when the approval adds no row, since it rewrites the table and enables the module on the way through.

None of this said anything anywhere. The refusal path had no log line at all, so a scope request that could never be granted left no trace in the daemon log, in logcat or on screen — which is why the framework case went unnoticed for as long as it did. The packages that did not resolve and the ones that were approved are both named now.

No new strings: xposed_module_request_scope_content takes the requested package as %3$s and accepts the list joined into it unchanged, so no translation changes.

…e dropped

"system" is the framework rather than a package: it names system_server, which
belongs to no package and resolves for nobody. The receiver looked the requested
package up before acting on the button, so every framework prompt died there --
the approval the user had just given was answered "Package not found", the
request was closed, its notification cancelled and no row written. The approve
branch normalises "system" to user 0, and that line could never once have run.
Accept the framework name without asking the package manager, and move the
lookup under "approve", which is the only answer that has to name something
real: deny and the one-hour timeout were reported as "Package not found" too
when a package had been uninstalled while the prompt was up, which told the
module the opposite of what had happened.

One request is now one prompt. The interface takes a list and a single
IXposedScopeCallback for it, and the client library's listener is documented to
run "when the request is completed", but the daemon put one prompt per package
on screen and answered each in its own right: a module asking for three packages
made the user answer three questions and then fired that one listener three
times, and a module that took the first answer as the answer acted on a third of
it. The whole list goes up as one prompt whose Approve answers for all of it,
deduplicated and sorted so that the same set asked twice replaces its own prompt
rather than stacking a second copy of the same question, and the per-module
ceiling now bounds calls rather than packages. What the user gives away in one
press is what the prompt lists, so it lists all of them; the notification reuses
the string it always did, with the packages joined into it, so no translation
changes.

An approval was thrown away when the module's process had died. A prompt sits
for an hour and the app a module runs inside can be killed at any point in it,
and the receiver returned on a dead callback binder before claiming the answer
or cancelling the notification: the user pressed Approve, nothing was written,
and the prompt stayed on screen with live buttons that did nothing for the rest
of the hour. An approval is a decision about the module's scope and is recorded
whether or not the module is still there to be told, deny and the timeout still
take the prompt down, and the only call that can fail against a dead module is
caught where it is made.

None of this said anything anywhere. The refusal path had no log line at all, so
a scope request that could never be granted left no trace in the daemon log, in
logcat or on screen, and the framework case above went unnoticed for as long as
it did for that reason. Name the packages that did not resolve, and the ones
that were approved.
@JingMatrix
JingMatrix merged commit ebec7b0 into master Aug 7, 2026
1 check passed
JingMatrix added a commit that referenced this pull request Aug 7, 2026
Four faults on the daemon side of a module's scope request.

The framework could never be granted. "system" names system_server and belongs
to no package, but the receiver resolved the requested package before acting on
the button, so every framework prompt was answered "Package not found", closed
and cancelled with no row written. Accept the framework name without asking the
package manager, and do the lookup only under Approve, the one answer that has
to name something real; deny and the one-hour timeout no longer report a lookup
failure for a package uninstalled while the prompt was up.

One request is now one prompt. The interface takes a list and a single
IXposedScopeCallback for it, but the daemon put one prompt per package on screen
and answered each in its own right, so a module asking for three packages made
the user answer three questions and fired that one listener three times. The
whole list goes up as one prompt whose Approve answers for all of it,
deduplicated and sorted so the same set asked twice replaces its own prompt, and
the per-module ceiling bounds calls rather than packages. The notification reuses
the string it always did with the packages joined into it, so no translation
changes.

An approval survives a dead module. A prompt sits for an hour and the app a
module runs inside can be killed in it, and the receiver returned on a dead
callback binder before claiming the answer, leaving nothing written and the
prompt on screen with buttons that did nothing. The decision is recorded whether
or not the module is still there to be told, and the only call that can fail
against it is caught where it is made.

The refusal path is logged. It had no log line at all, so a request that could
never be granted left no trace anywhere, which is why the framework case went
unnoticed for as long as it did. Name the packages that did not resolve, and the
ones that were approved.
@JingMatrix
JingMatrix deleted the scope-request-answers branch August 7, 2026 19:31
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