CVE-2025-32348 AI-generated analysis
platform/frameworks/base, WindowManager / ActivityTaskManager background activity launch (BAL) control
Stops treating a process whose only visible activity is in pinned (PIP) windowing mode as "has a visible window / foreground task" for background activity launch (BAL) exemptions. It does this by adding VisibleActivityProcessTracker.hasVisibleNotPinnedActivity and an inPinnedWindow parameter to BackgroundLaunchProcessController.areBackgroundActivityStartsAllowed.
Root cause
BackgroundActivityStartController computed callingUidHasAnyVisibleWindow / realCallingUidHasAnyVisibleWindow via mService.hasActiveVisibleWindow(uid). Per index, ActivityTaskManagerService.hasActiveVisibleWindow returns true when mVisibleActivityProcessTracker.hasVisibleActivity(uid) or mActiveUids.hasNonAppVisibleWindow(uid) is true. hasVisibleActivity matched any visible process of the uid, including one whose activity is in pinned (picture-in-picture) windowing mode, so such a caller got BAL_ALLOW_VISIBLE_WINDOW. Likewise, BackgroundLaunchProcessController.areBackgroundActivityStartsAllowed returned BAL_ALLOW_FOREGROUND whenever hasActivityInVisibleTask was true, without checking the process's windowing mode. A pinned-window process therefore also qualified via the "activity in foreground task" path, so a PIP window enabled background activity starts.
How the fix works
- services/core/java/com/android/server/wm/VisibleActivityProcessTracker.java: adds hasVisibleNotPinnedActivity(int uid), which calls match(uid, wpc -> !wpc.inPinnedWindowingMode()). hasVisibleActivity now passes an ALWAYS_TRUE predicate, and match() no longer accepts a null predicate (predicate.test(wpc) is unconditional).
- services/core/java/com/android/server/wm/BackgroundActivityStartController.java (region computing callingUidHasAnyVisibleWindow): replaces mService.hasActiveVisibleWindow(callingUid) with mService.mVisibleActivityProcessTracker.hasVisibleNotPinnedActivity(callingUid) || mService.mActiveUids.hasNonAppVisibleWindow(callingUid). The same substitution is made for realCallingUidHasAnyVisibleWindow when callingUid != realCallingUid. Non-app visible windows (e.g. live wallpaper) keep their exemption; only the activity-based part now excludes pinned processes.
- services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java:areBackgroundActivityStartsAllowed: adds a boolean parameter inPinnedWindow after hasActivityInVisibleTask. The foreground-task exemption becomes (isCheckingForFgsStart || !inPinnedWindow) && hasActivityInVisibleTask && appSwitchState != APP_SWITCH_DISALLOW. A pinned-window process therefore no longer gets BAL_ALLOW_FOREGROUND for activity starts, but still does when the check is for a foreground service start. The app-switch condition is rewritten from (== APP_SWITCH_ALLOW || == APP_SWITCH_FG_ONLY) to != APP_SWITCH_DISALLOW, with the import changed to match; the Android 15 base already used != APP_SWITCH_DISALLOW.
- services/core/java/com/android/server/wm/WindowProcessController.java:areBackgroundActivityStartsAllowed(int, boolean): passes inPinnedWindowingMode() as the new argument.
- services/tests/wmtests/src/com/android/server/wm/VisibleActivityProcessTrackerTests.java: new tests asserting that a WINDOWING_MODE_PINNED process is reported by hasVisibleActivity but not by hasVisibleNotPinnedActivity.
- Follow-up on Android 14: commits 58a95019e245 (android-security-14.0.0_r24) and 4e7b14350ece (android-security-14.0.0_r25), both with Change-Id Iff954bf96857cdf5cafdc7bcf28908c1c6cb20a7, fully revert the change, citing an app compatibility regression. The code shown at android-security-14.0.0_r29 nevertheless contains the fixed logic: hasVisibleNotPinnedActivity in BackgroundActivityStartController, ALWAYS_TRUE in the tracker, the inPinnedWindowingMode() argument in WindowProcessController, and the APP_SWITCH_DISALLOW import. The test file at r29 also has extra imports (doReturn, when). This points to a later re-land whose commit is not in the material.
Completeness
- Covers both the callingUid and realCallingUid visible-window exemptions in BackgroundActivityStartController and the foreground-task exemption in BackgroundLaunchProcessController.areBackgroundActivityStartsAllowed.
- By design, the foreground-task exemption still applies to pinned processes when isCheckingForFgsStart is true (the WindowProcessController.areBackgroundFgsStartsAllowed path). Pinned windows therefore still count toward permission to start a foreground service from the background.
- The pinned check is per process (WindowProcessController.inPinnedWindowingMode()), not per activity. The material does not show how a process with both a pinned and a non-pinned visible activity is classified.
- Per index, ActivityTaskManagerService.hasActiveVisibleWindow itself is unchanged and still uses hasVisibleActivity. Only the BAL controller call sites were switched to the not-pinned variant, so other users of hasActiveVisibleWindow keep the old behavior.
- On Android 15 the fix also covers both branches of the real-caller check (balImproveRealCallerVisibilityCheck true and false). The 15 metrics call now passes mCallingUidHasVisibleActivity / mRealCallingUidHasVisibleActivity (hasVisibleActivity only, which still counts pinned activities but no longer counts non-app visible windows).
Behavior changes
- An app whose only visible activity is in picture-in-picture (pinned) mode is now blocked (BAL_BLOCK) on the visible-window and foreground-task paths, unless another exemption applies. The commit was reverted once on Android 14 for an app compatibility regression, so PIP apps that start activities will see a change.
- BAL verdict messages: on 16, the caller and real-caller messages become "callingUid has visible non-pinned window" / "realCallingUid has visible non-pinned window". On 15, only the caller message changes. On 15 and 16, BalState.toString gains the callingUidHasVisibleNotPinnedActivity and realCallingUidHasVisibleNotPinnedActivity fields.
- VisibleActivityProcessTracker.match no longer tolerates a null predicate. It would throw a NullPointerException if any other caller passed null; no such caller is shown in the material.
- The signature of BackgroundLaunchProcessController.areBackgroundActivityStartsAllowed changes (new inPinnedWindow parameter), which affects any out-of-tree callers or tests.
Per major
- Android 14: Same fix (RESTRICT AUTOMERGE cherry-pick 4ec3e4cea49d) in android-security-14.0.0_r22. Fully reverted in r24 (58a95019e245) and r25 (4e7b14350ece) for an app compatibility regression. The code at android-security-14.0.0_r29 shows the fixed logic present again (7/8 patched lines); the re-land commit is not in the material.
- Android 15: Adapted fix (483fba0b4777, RESTRICT AUTOMERGE) in android-security-15.0.0_r10. BalState gains mCallingUidHasVisibleNotPinnedActivity / mRealCallingUidHasVisibleNotPinnedActivity, and both the flagged and unflagged real-caller checks use the not-pinned variant. inPinnedWindow is added to BackgroundLaunchProcessController, a BalVerdict(int,String) constructor is added, and many tests are updated. 7/8 lines present at android-security-15.0.0_r17.
- Android 16: Adapted fix (b96d7a515e9e, not RESTRICT AUTOMERGE) in android-security-16.0.0_r1. Same BalState changes. The foreground-task exemption is gated on checkConfiguration.isCheckingForFgsStart || !inPinnedWindow, together with checkConfiguration.checkOtherExemptions. 8/8 lines present at android-security-16.0.0_r8.
- Android 17: Unclear. The resolver lists 17 as resolved (base, android-17.0.0_r1), but the linked commit 58822cb0d7e4 is itself a Revert of "Ignore pinned Windows". It touches ActivityStarter.java and a boolean-returning BackgroundLaunchProcessController, a code shape unlike 14/15/16, and the patched region is 0/8 present at android-security-17.0.0_r1. The material does not show whether 17 carries the fix in another form.
Unknowns
- The commit that re-landed the fix on Android 14 after the r24/r25 reverts, and what was changed to address the app compatibility regression.
- The actual fix state on Android 17: the resolver says resolved, but only a revert commit is linked and the patched region is absent at android-security-17.0.0_r1.
- Which of the 8 patched-region lines differs on 14 r29 and 15 r17 (7/8 present).
- The exact enclosing method name in BackgroundActivityStartController for the Android 14 hunk (the hunk header shows only the class).
- The bulletin lists the type as DoS; the material does not show the concrete impact scenario.