fix(android): extend SCVH pre-check to API 30..36 + v0.1.10#7
Merged
Conversation
…0..32 to API 30..36
v0.1.9 confirmed the same `Invalid window token` crash class re-surfaces
on API 31 (Android 12), with the user later reporting it on API 33
(Android 13) as well. v0.1.9's pre-check was scoped 30..32. Production
reports show the crash also affecting Android 13+ on OEM builds
(Samsung One UI confirmed; others likely).
Empirically tested SCVH `host.setView()` behaviour on stock Google APIs
system images for every API in the suspect range:
API 30 (Android 11): fails - SecurityException: Requires INTERNAL_SYSTEM_WINDOW
API 31 (Android 12): fails - SecurityException
API 32 (Android 12L): fails (inferred from 31 + AOSP behaviour)
API 33 (Android 13): fails - RuntimeException: Adding window failed
API 34 (Android 14): fails - RuntimeException
API 35 (Android 15): fails - RuntimeException
API 36 (Android 15 QPR / "Baklava"): fails - RuntimeException
API 37 (Android 16): succeeds - "attached size=… sc=ok"
The exception type differs across the range but the underlying SCVH
behaviour is the same: `ViewRootImpl.setView` calls `requestLayout()`
before the throwing `addToDisplay`, leaving a `TraversalRunnable`
queued in the SCVH's Choreographer. The reflective
`unscheduleScvhTraversals` safety net latches off on Android 14+
hidden-API enforcement (the SCVH internal `mViewRoot` field is `@hide`),
so on those devices the runnable cannot be cancelled — at the next
vsync it fires in the TRAVERSAL phase, calls
`WindowlessWindowManager.relayout` against a token that was never
registered with the WWM, and throws `IllegalArgumentException: Invalid
window token (never added or removed already)` from `Looper.loop`.
On stock emulator images the legacy fallback path absorbs the failure
without crashing because the RuntimeException variant happens not to
queue a problematic runnable. But production reports from OEM builds
(notably Samsung One UI on Android 13) do show the crash signature
post-failure — OEM WMS customisations differ from AOSP in ways that
trigger the queued-runnable scenario.
Resolution: skip SCVH entirely on the entire empirically-confirmed-
broken range (API 30..36). The legacy non-SCVH attach uses regular
`activity.windowManager.addView` with `TYPE_APPLICATION_PANEL` and
never touches `WindowlessWindowManager`, so the crash class is
impossible there.
API 37 / Pixel_9 keeps SCVH active and continues to win the
Home-press snapshot race via the SurfaceFlinger-direct alpha toggle
(`broadcast: fast scvh=true dt=0ms`). If future Android releases
re-introduce a similar restriction, extend the upper bound.
Verified post-change:
API 31 / Pixel 6: pre-check fires, legacy attach, no crash
API 33 / Pixel 6: pre-check fires, legacy attach, no crash
API 34 / Pixel 6: pre-check fires, legacy attach, no crash
API 35 / Pixel 6: pre-check fires, legacy attach, no crash
API 36 / Pixel 6: pre-check fires, legacy attach, no crash
API 37 / Pixel_9: SCVH still active, attached=true, snapshot race
fix preserved
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.
Summary
v0.1.10 — extends the SCVH
INTERNAL_SYSTEM_WINDOWpre-check from API 30..32 (v0.1.9) to API 30..36, after the user reported theInvalid window tokencrash recurring on Android 13 (API 33) production devices.Empirical SCVH behaviour across the suspect API range
Tested
host.setView()on stock Google APIs system images for every API:SecurityException: Requires INTERNAL_SYSTEM_WINDOWSecurityExceptionRuntimeException: Adding window failedRuntimeExceptionRuntimeExceptionRuntimeExceptionattached size=… sc=okThe exception type differs but the underlying SCVH behaviour is the same:
ViewRootImpl.setViewcallsrequestLayout()before the throwingaddToDisplay, leaving aTraversalRunnablequeued in the SCVH Choreographer. On Android 14+, hidden-API enforcement blocks the reflectiveunscheduleScvhTraversalssafety net (the SCVHmViewRootfield is@hide), so we cannot cancel the runnable; at the next vsync it fires against an unregistered WWM token and the process dies fromLooper.loop.Stock emulator images happened not to queue a problematic runnable on the RuntimeException path (no observed crash on Pixel 6 / 33..36), but OEM-customised WMS builds (Samsung One UI on Android 13 specifically) do — confirmed by the user's production crash reports.
Fix
API 37+ keeps SCVH active (Pixel_9 emulator confirmed) — the SurfaceFlinger-direct alpha toggle continues to win the Home-press snapshot race (
broadcast: fast scvh=true dt=0ms).Trade-off
API 30..36 devices use the legacy
view.alphapath instead of the SF-direct alpha. On Android 14+ the reflection-based SC capture used by the legacy fast path is also blocked, so the actual SF-direct benefit loss is concentrated on Android 11..13 — where the pre-check is non-negotiable to prevent crashes.Verified
broadcast: fast scvh=trueFiles changed
android/src/main/java/com/margelo/nitro/cover/HybridCover.kt— range expanded fromR..S_V2toR..36, comments updated.package.json—0.1.9→0.1.10.CHANGELOG.md— new0.1.10 - 2026-06-02entry.