CVE-2025-48546 AI-generated analysis
platform/frameworks/base, WindowManager / ActivityTaskManager (services/core/java/com/android/server/wm/SafeActivityOptions.java)
SafeActivityOptions now rejects with a SecurityException any activity start whose ActivityOptions carry setLaunchWindowingMode(WINDOWING_MODE_PINNED), pointing callers to ActivityOptions#makeLaunchIntoPip instead.
Root cause
SafeActivityOptions validated several caller-controlled ActivityOptions fields (e.g. launch activity type gated on isSystemOrSystemUI; remote transition, per the existing SafeActivityOptionsTest cases) but did not validate the launch windowing mode. A caller could set WINDOWING_MODE_PINNED through ActivityOptions#setLaunchWindowingMode, and the removed tests testKeepsPictureInPictureLaunchModeInOptions and testKeepsPictureInPictureLaunchModeWithBoundsInOptions in TaskLaunchParamsModifierTests show that TaskLaunchParamsModifier kept WINDOWING_MODE_PINNED from the options (with or without launch bounds). The new comment names ActivityOptions#makeLaunchIntoPip as the public API to use instead. The bulletin rates this High / EoP.
How the fix works
- services/core/java/com/android/server/wm/SafeActivityOptions.java (the validation method that emits 'Permission Denial: starting ...' messages; the method name is not shown in the hunk header): adds a check after the existing permission-denial block and before the launch-activity-type check. If options.getLaunchWindowingMode() == WINDOWING_MODE_PINNED, it builds a 'Permission Denial ... with setLaunchWindowingMode=PINNED' message with the intent, callerApp, callingPid and callingUid, logs it with Slog.w(TAG, msg) and throws new SecurityException(msg).
- Within the hunk the check has no caller condition: unlike the adjacent activity-type check it is not gated on isSystemOrSystemUI or a permission. The comment directs callers to ActivityOptions#makeLaunchIntoPip.
- Adds a static import of android.app.WindowConfiguration.WINDOWING_MODE_PINNED.
- services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java: removes testKeepsPictureInPictureLaunchModeInOptions and testKeepsPictureInPictureLaunchModeWithBoundsInOptions, which asserted the now-rejected behavior.
- On Android 15 and 16 the commit also adds a regression case in SafeActivityOptionsTest.java (ActivityOptions.makeBasic(); setLaunchWindowingMode(WINDOWING_MODE_PINNED); verifySecureExceptionThrown). The Android 14 commit does not include this test change.
Completeness
- Covers exactly one field: options.getLaunchWindowingMode() == WINDOWING_MODE_PINNED, checked at this validation point in SafeActivityOptions. An activity start whose ActivityOptions go through this check can no longer request PINNED.
- Other windowing modes requested via setLaunchWindowingMode are not restricted by this change; only PINNED is rejected.
- The public PiP route (ActivityOptions#makeLaunchIntoPip) is untouched; its own validation is not part of this diff.
- Whether any activity-start path consumes ActivityOptions without going through this SafeActivityOptions validation is not shown in the material.
Behavior changes
- An activity start validated by this method whose ActivityOptions set setLaunchWindowingMode(WINDOWING_MODE_PINNED) now gets a SecurityException. Before the fix, the removed tests show TaskLaunchParamsModifier kept the PINNED mode.
- A new Slog.w line 'Permission Denial: starting <intent> from <callerApp> (pid=, uid=) with setLaunchWindowingMode=PINNED' is logged on rejection.
- The check runs before the launch-activity-type check, so a PINNED request is rejected whatever activity type is supplied.
Per major
- Android 14: same fix: commit 41bdf43266da in android-security-14.0.0_r22 (RESTRICT AUTOMERGE cherry-pick, Change-Id I9d37d41af3d86f785fd5d85503b544552b39cac4). Adds the PINNED check in SafeActivityOptions.java and removes two TaskLaunchParamsModifierTests; does not include the SafeActivityOptionsTest regression case. 8/8 patched lines present at android-security-14.0.0_r29.
- Android 15: same fix: commit 8b660e887005 in android-security-15.0.0_r10, identical SafeActivityOptions.java hunk at a different offset, plus removal of the two TaskLaunchParamsModifierTests and a PINNED regression case in SafeActivityOptionsTest.java. 8/8 lines present at android-security-15.0.0_r17.
- Android 16: same fix: commit 3668e1d4bbec in android-security-16.0.0_r1, identical SafeActivityOptions.java hunk plus the same test changes as Android 15. 8/8 lines present at android-security-16.0.0_r8.
- Android 17: not affected (not listed by the bulletin); the patched region (8/8 lines) is present at android-security-17.0.0_r1.
Unknowns
- The exact name of the SafeActivityOptions method containing the new check (the hunk header shows only the class).
- Which callers or start paths could reach the unchecked PINNED launch, and what permissions they needed; the material shows only the removed TaskLaunchParamsModifier tests.
- Whether every caller (including system/SystemUI) reaches this check, and whether any activity-start path bypasses SafeActivityOptions validation.