CVE-2025-32349 AI-generated analysis
platform/frameworks/base, WindowManager (services/core/java/com/android/server/wm: DisplayPolicy, WindowState, WindowStateAnimator)
WindowManager now forces the default Animation_Toast style on TYPE_TOAST windows from sessions without mCanAddInternalSystemWindow, and uses a fixed short alpha fade instead of the window's own exit animation when a non-system overlay is forcibly hidden, so an app can no longer control how long its overlay stays on screen during a forced hide.
Root cause
In DisplayPolicy.adjustWindowParamsLw, the TYPE_TOAST case clamped hideTimeoutMilliseconds to TOAST_WINDOW_TIMEOUT and set FLAG_NOT_TOUCHABLE, but left attrs.windowAnimations as the app supplied it. Per the commit message, legacy apps and deprecated custom-view toasts show TYPE_TOAST windows from their own process, so an untrusted app could attach arbitrary WindowManager.LayoutParams#windowAnimations. WindowState.setForceHideNonSystemOverlayWindowIfNeeded(true) applies to system alert window types and TYPE_TOAST from sessions lacking mCanAddInternalSystemWindow. When it ran for such a window it called hide(true /* doAnimation */, true). Per the second commit message, the window's specified exit animation could then be used, so the forced hide could run for a caller-chosen duration instead of a short, system-defined one. The commit message notes that regular text toasts (target API 30+) are drawn by SystemUI, which has the internal permission and is unaffected.
How the fix works
- Commit a93c95a17ae4 (Do not allow custom animation of untrusted Toast), DisplayPolicy.java:adjustWindowParamsLw, case TYPE_TOAST: after forcing FLAG_NOT_TOUCHABLE, adds `if (!win.mSession.mCanAddInternalSystemWindow) attrs.windowAnimations = R.style.Animation_Toast;`. Any TYPE_TOAST window from a session without the internal-system-window capability gets the stock toast animation style. The commit message cites config_longAnimTime=500ms for hiding.
- Commit b8401310e97f (Use consistent animation when forcibly hiding non system overlay), WindowState.java: adds the package-private getter `isForceHiddenNonSystemOverlayWindow()`, which returns the existing mForceHideNonSystemOverlayWindow field. setForceHideNonSystemOverlayWindowIfNeeded sets that field for system-alert-type and TYPE_TOAST windows from non-internal sessions, excluding system application overlays with mCanCreateSystemApplicationOverlay.
- Same commit, WindowStateAnimator.java, in the animation-selection code containing the `switch (transit)` / TRANSIT_ENTER cases: inserts `else if (!isEntrance && mWin.isForceHiddenNonSystemOverlayWindow())` after a branch that loads an animation via AnimationUtils.loadAnimation(mContext, anim) and before the `switch (transit)` branch. In that case it builds `new AlphaAnimation(1f, 0f)` with duration `config_shortAnimTime`. Also adds the AlphaAnimation import.
Completeness
- Commit 1 only touches the TYPE_TOAST case of adjustWindowParamsLw; other window types keep their caller-supplied windowAnimations. The gate is the session's mCanAddInternalSystemWindow, so trusted sessions keep custom toast animations.
- Commit 2 applies only to the exit direction (!isEntrance) and only while mForceHideNonSystemOverlayWindow is true, i.e. for the window types handled by setForceHideNonSystemOverlayWindowIfNeeded. For non-toast overlays (e.g. system alert windows), entrance animations and non-forced hides are not changed by these commits. Untrusted toasts are covered by commit 1 in all cases.
- In commit 2 the new branch is an else-if after the branch that calls AnimationUtils.loadAnimation(mContext, anim), so an animation loaded by that preceding branch still takes precedence over the fixed fade. That branch's condition is not shown.
- The existing hideTimeoutMilliseconds clamp to TOAST_WINDOW_TIMEOUT is unchanged; the fix adds the animation dimension that was not previously constrained.
- setHiddenWhileSuspended (a sibling path in WindowState, visible in the context) is not changed by either commit. The material does not show whether it has the same animation exposure.
Behavior changes
- TYPE_TOAST windows added by sessions without mCanAddInternalSystemWindow always animate with R.style.Animation_Toast; adjustWindowParamsLw overwrites any WindowManager.LayoutParams#windowAnimations set by the app.
- When a non-system overlay or untrusted toast is forcibly hidden via setForceHideNonSystemOverlayWindowIfNeeded, it fades out with a fixed AlphaAnimation(1f, 0f) lasting config_shortAnimTime, unless the preceding loadAnimation branch applies. The commit message says this avoids jump cuts and inconsistent durations.
- No new error paths or exceptions; the changes only affect animation selection.
Per major
- Android 14: same fix: both commits (a93c95a17ae4 DisplayPolicy; b8401310e97f WindowState + WindowStateAnimator) in android-security-14.0.0_r22; 8/8 patched lines present at android-security-14.0.0_r29.
- Android 15: same fix for the DisplayPolicy commit: 394acf2aa1da in android-security-15.0.0_r10, identical hunk at a different offset (line ~974); 4/4 patched lines present at android-security-15.0.0_r17. The material does not show the WindowStateAnimator/WindowState commit for this branch.
- Android 16: same fix for the DisplayPolicy commit: 3a76075721bb in android-security-16.0.0_r1, identical hunk at line ~985; 4/4 patched lines present at android-security-16.0.0_r8. The material does not show the WindowStateAnimator/WindowState commit for this branch.
- Android 17: not affected per the bulletin (not listed); the patched DisplayPolicy region is present 4/4 at android-security-17.0.0_r1.
Unknowns
- Whether the WindowState/WindowStateAnimator commit (b8401310e97f) was applied on Android 15 and 16; only the DisplayPolicy commit is shown for those branches.
- Which system flows call setForceHideNonSystemOverlayWindowIfNeeded(true), beyond the Settings launch in the commit test; the callers are not in the material.
- The exact name of the enclosing method in WindowStateAnimator and the condition of the branch that precedes the new else-if.
- How the `switch (transit)` branch resolves animations from window attributes; the material only shows its start.
- Whether the setHiddenWhileSuspended path has a comparable animation exposure; the material does not show its hide call or animation handling.