CVE-2026-0061 AI-generated analysis
platform/frameworks/base, WindowManager (services/core/java/com/android/server/wm/WindowState.java)
WindowState now applies the server-side visibility policy (hide/show) to the WindowState's own mSurfaceControl through the pending transaction, in addition to the existing mWinAnimator handling, so policy visibility no longer depends only on a surface the client can access.
Root cause
In WindowState, the legacy policy visibility (LEGACY_POLICY_VISIBILITY) was applied through mWinAnimator.hide(...) / mWinAnimator.applyAnimationLocked(...), and the WindowState's own surface (mSurfaceControl) was never hidden or shown by the policy code in checkPolicyVisibilityChange(), show() or hide(). Per the commit message, the client side can access the ViewRootImpl surface and change its visibility, so the server-side policy should control the surface the client cannot access (the WindowState surface). The commit's test scenario is an overlay window that should not be visible when Settings is launched.
How the fix works
- WindowState.java:checkPolicyVisibilityChange(): after mWinAnimator.hide(...) when !isVisibleByPolicy(), additionally call getPendingTransaction().hide(mSurfaceControl) if mSurfaceControl != null.
- WindowState.java:show(): after setPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY) and mLegacyPolicyVisibilityAfterAnim = true, call getPendingTransaction().show(mSurfaceControl) if mSurfaceControl != null, before the optional TRANSIT_ENTER animation.
- WindowState.java:hide(): inside the hide block, after the mFocusMayChange bookkeeping ('WindowState.hideLw: setting mFocusMayChange true'), call getPendingTransaction().hide(mSurfaceControl) if mSurfaceControl != null.
- WindowStateTests.java:testIsOnScreen_hiddenByPolicy: adds verify(mTransaction).hide(window.mSurfaceControl) after hide(false,false), clearInvocations(mTransaction), and verify(mTransaction).show(window.mSurfaceControl) after show(false,false).
Completeness
- Adds mSurfaceControl hide/show in three places in WindowState: hide(), checkPolicyVisibilityChange() (whose debug message refers to policy visibility changing after animation), and show().
- The test only verifies the new surface calls for the non-animated hide/show; the animated hide path is not checked for the mSurfaceControl hide.
- All three additions are guarded by mSurfaceControl != null; the material does not show how a WindowState whose surface is created after a policy hide is handled.
- Only these three methods are changed; any other code that sets or clears policy visibility flags directly is not touched in the diff.
- The client-side ability to change the ViewRootImpl surface visibility is not removed; per the commit message the fix moves policy control onto the WindowState surface instead.
Behavior changes
- Policy-hidden windows now also have their WindowState surface (mSurfaceControl) hidden in the pending transaction.
- Policy show now explicitly issues a show on mSurfaceControl in the pending transaction.
- Additional hide/show calls on the WindowState SurfaceControl per policy transition; no new error codes or API changes in the diff.
Per major
- Android 14: same fix: b53981d87f80 in android-security-14.0.0_r28 (Cherrypick-From 52bfa5a16ecc, Change-Id I326fcaf71f901a11cf4aee3d734494090a1d0fb3); context uses mWinAnimator.hide(getGlobalTransaction(), ...). 8/8 lines of the patched region present at android-security-14.0.0_r29.
- Android 15: same fix: 0922d84b1c64 in android-security-15.0.0_r16; same three code hunks, surrounding context uses getPendingTransaction() for mWinAnimator.hide and the test context uses ANIMATION_TYPE_TOKEN_TRANSFORM. 8/8 lines present at android-security-15.0.0_r17.
- Android 16: same fix: 4518f78f8b34 in android-security-16.0.0_r7; same three code hunks at different line offsets. 8/8 lines present at android-security-16.0.0_r8.
- Android 17: same fix: e58fd9cd11e4 in android-17.0.0_r1 (base); same three code hunks. At android-security-17.0.0_r1 the resolver reports 7/8 lines of the patched region present; the material does not show which line differs.
Unknowns
- Exactly how the client side changes the ViewRootImpl surface visibility is not shown (only stated in the commit message).
- Which policy path triggers hide() in the reported overlay/Settings scenario is not shown in the diff.
- Whether the hide() hunk is in the animated or non-animated branch, and whether checkPolicyVisibilityChange() covers the animated hide case for mSurfaceControl.
- The surface hierarchy between mSurfaceControl and the client surface.
- Why the Android 17 security tag shows 7/8 rather than 8/8 lines of the patched region.
- Whether a surface created after a policy hide (mSurfaceControl null at hide time) inherits the hidden state.