Move ContentScopeScripts inbound JS messages off the JavaBridge thread - #9350
Merged
anikiki merged 2 commits intoAug 4, 2026
Conversation
7 tasks
Contributor
Author
This stack of pull requests is managed by Graphite. Learn more about stacking. |
This was referenced Jul 30, 2026
anikiki
marked this pull request as ready for review
July 31, 2026 13:35
anikiki
force-pushed
the
feature/ana/drop_defensive_copyonwritearraylist_from_the_optimized_realcontentscopescripts
branch
from
July 31, 2026 14:50
80bb528 to
605346c
Compare
anikiki
force-pushed
the
feature/ana/improve_the_jsmessaging_bridge_for_contentscopescriptsjsmessaging
branch
from
July 31, 2026 14:50
348dfe5 to
0b7fe7f
Compare
CrisBarreiro
approved these changes
Aug 3, 2026
| import javax.inject.Named | ||
|
|
||
| // Backstop against unbounded growth, not a tuning parameter: observed depth on real pages is 0-1. | ||
| internal const val MAX_QUEUED_MESSAGES = 512 |
Collaborator
There was a problem hiding this comment.
Can we use an RC flag settings in case this causes issues in the future? I see we have an RC that acts as a kill-switch, but that would. require to keep the duplicated code forever
Contributor
Author
There was a problem hiding this comment.
@CrisBarreiro We're not looking to fine-tune this value, that's why I didn't add this value as a RC flag setting. The value (intentionally high) is added as a cap in case something very bad happens and at that point we also send a pixel. We'd turn off this if we see issues as this queue should have at most a few values in it.
Contributor
|
Privacy Review task: https://app.asana.com/0/69071770703008/1217127027704861 |
Base automatically changed from
feature/ana/drop_defensive_copyonwritearraylist_from_the_optimized_realcontentscopescripts
to
develop
August 4, 2026 11:57
JavaBridge calls are synchronous from the page's point of view, so every inbound contentScopeScripts message blocked the page's JS thread for as long as native took to route it. The url read alone was a runBlocking hop to the main thread, and Moshi parsed JsMessage reflectively. process() now only parses and enqueues, and a single consumer drains the queue off the JavaBridge thread, so handlers still see messages one at a time and in the order the page sent them. The url of the sending document is sampled when a message arrives rather than when it is handled, because a page can navigate while its message is still queued and the domain check has to apply to the document that sent it. Handlers are indexed by feature name and method so routing does not build every registered handler, and JsMessage is parsed with JSONObject instead of reflective Moshi. Enqueueing removes the backpressure the synchronous call used to provide, so the queue is bounded and overflow is reported by a daily pixel. The whole path is behind optimizeContentScopeMessaging, which is sampled when the interface is attached; with the flag off, process() takes the path exactly as it shipped. Task/Issue URL: https://app.asana.com/1/137249556945/project/1200581511062568/task/1216755882810224
anikiki
force-pushed
the
feature/ana/improve_the_jsmessaging_bridge_for_contentscopescriptsjsmessaging
branch
from
August 4, 2026 19:02
0b7fe7f to
79118fd
Compare
anikiki
deleted the
feature/ana/improve_the_jsmessaging_bridge_for_contentscopescriptsjsmessaging
branch
August 4, 2026 19:24
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.

Task/Issue URL: https://app.asana.com/1/137249556945/task/1216755882810224?focus=true
Tech Design URL (if applicable):
API Proposals URL(s) (if applicable):
Description
Inbound contentScopeScripts JS messages were routed to their handlers on the WebView JavaBridge thread. Because JavaBridge calls are synchronous from the page's point of view, the page's JS thread was blocked for the whole round trip — including a runBlocking hop to the main thread just to read the document url, and reflective Moshi parsing of every message.
process() now only parses and enqueues; a single consumer drains the queue off the JavaBridge thread, so handlers still see messages one at a time in the order the page sent them. The sending document's url is sampled on arrival rather than at handling time, so domain-restricted features are still checked against the document that actually sent the message. Handler lookup is indexed by feature name and method, and parsing uses JSONObject instead of Moshi.
Enqueueing removes the backpressure the synchronous call provided, so the queue is bounded (512) and overflow fires a daily m_content_scope_scripts_inbound_queue_full pixel.
All of it sits behind optimizeContentScopeMessaging, sampled when the JS interface is attached. With the flag off, process() runs exactly as it shipped.
Steps to test this PR
The flag defaults to enabled on internal builds, and is sampled at WebView attach — so after flipping it, open a new tab or restart the app.
Queue overflow isn't reachable by hand (observed depth on real pages is 0–1); it's covered by unit tests in ContentScopeScriptsJsMessagingTest.
NO UI changes
Note
Medium Risk
Touches core WebView JS bridge routing for privacy/content-scope features with async ordering and queue drops on overflow, but behavior is gated behind an internal-default kill-switch and legacy path remains unchanged when disabled.
Overview
Inbound contentScopeScripts messages no longer run handlers on the WebView JavaBridge thread. With
optimizeContentScopeMessagingenabled (sampled at JS interface attach),process()only parses and enqueues; a single consumer on IO drains a bounded queue (512) so handlers still run in order, one at a time.The optimized path uses JSONObject parsing instead of Moshi, indexes handlers by feature/method, and snapshots the sending document URL on enqueue (not at handle time) for domain checks. Overflow drops messages and fires daily
m_content_scope_scripts_inbound_queue_full.Registrationpairs WebView + callback so stale queued work is dropped on re-register. The flag off path keeps the previous synchronousprocessLegacybehavior.Reviewed by Cursor Bugbot for commit 79118fd. Bugbot is set up for automated code reviews on this repo. Configure here.