Low chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInappropriate implementation in Media
DescriptionInappropriate implementation in Media
ComponentMedia
Bug ClassLogic Error
Tracker520663771
Fix commit5e7d3e1916e8 (chromium/src) +28/-19
CISA KEVNot listed
CreditedGoogle
Disclosed2026-07-29

Changed Functions

FunctionChangeNotes
if
chrome/android/java/src/org/chromium/chrome/browser/media/FullscreenVideoPictureInPictureController.java
modified

Files Changed

  • chrome/android/java/src/org/chromium/chrome/browser/media/FullscreenVideoPictureInPictureController.java
  • chrome/android/junit/src/org/chromium/chrome/browser/media/FullscreenVideoPictureInPictureControllerUnitTest.java
  • components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java
  • content/browser/media/session/media_session_android.cc
  • content/browser/media/session/media_session_android.h
  • content/public/android/java/src/org/chromium/content/browser/MediaSessionImpl.java
  • content/public/android/java/src/org/chromium/content_public/browser/MediaSession.java
From 5e7d3e1916e8b3aeb95946172f12c1d7a071e1ed Mon Sep 17 00:00:00 2001
From: Phil Yan <[email protected]>
Date: Tue, 09 Jun 2026 09:17:24 -0700
Subject: [PATCH] [media] Parameterize MediaSession resume in Android JNI

The Android Auto-PiP media controller propagated system-initiated
events (such as screen-off dismissal or window stashing) as
user-initiated UI actions. This mismatch could potentially forge
a fresh user activation ('kInteraction') in Blink.

This CL fixes this logic by:
1. Parameterizing the JNI bridge `MediaSessionAndroid::Resume` and
   the Java class `MediaSession` to accept a `SuspendType` parameter.
2. Updating `FullscreenVideoPictureInPictureController` to pass
   `SuspendType.SYSTEM` during screen-off dismissal and stashing.
3. Updating all other usages, tests, and mocks accordingly.

Bug: 520663771
Change-Id: Ic87d5812b34174ae1061b75d09616493dbd8ba28
Fix: 520663771
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7910926
Reviewed-by: Ted Choc <[email protected]>
Reviewed-by: Frank Liberato <[email protected]>
Commit-Queue: Phil Yan <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1644023}
---

diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/FullscreenVideoPictureInPictureController.java b/chrome/android/java/src/org/chromium/chrome/browser/media/FullscreenVideoPictureInPictureController.java
index fc3e602..be6e9eb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/FullscreenVideoPictureInPictureController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/FullscreenVideoPictureInPictureController.java
@@ -307,7 +307,7 @@
         // `stashed`.  Also note that `mIsSuspendedForStash` can be reset elsewhere, to help to
         // account for missed events from Android.
         if (mIsPlaying && stashed && !mIsSuspendedForStash) {
-            mediaSession.suspend(SuspendType.UI);
+            mediaSession.suspend(SuspendType.SYSTEM);
             mIsSuspendedForStash = true;
         } else if (!mIsPlaying && !stashed && mIsSuspendedForStash) {
             // Don't resume if we didn't pause it on the transition into stash.  For example, don't
@@ -335,7 +335,7 @@
         if (mediaSession == null || mIsPlaying || !mIsSuspendedForStash) {
             return;
         }
-        mediaSession.resume();
+        mediaSession.resume(SuspendType.SYSTEM);
         mIsSuspendedForStash = false;
     }
 
@@ -636,7 +636,7 @@
             final MediaSession mediaSession = getMediaSession();
 
             if (mediaSession != null && mIsPlaying) {
-                mediaSession.suspend(SuspendType.UI);
+                mediaSession.suspend(SuspendType.SYSTEM);
             }
         }
     }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/FullscreenVideoPictureInPictureControllerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/FullscreenVideoPictureInPictureControllerUnitTest.java
index 3197fab9..7432370 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/media/FullscreenVideoPictureInPictureControllerUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/FullscreenVideoPictureInPictureControllerUnitTest.java
@@ -182,7 +182,7 @@
         // Stash while media is playing.
         mWebContentsObserverCaptor.getValue().mediaStartedPlaying(0, true, true);
         mController.onStashReported(true);
-        verify(mMediaSession, times(1)).suspend(SuspendType.UI);
+        verify(mMediaSession, times(1)).suspend(SuspendType.SYSTEM);
         mWebContentsObserverCaptor.getValue().mediaStoppedPlaying(0);
 
         // Un-stash while media is still paused.
@@ -191,7 +191,7 @@
                 FullscreenVideoPictureInPictureController.UNSTASH_DELAY_MILLIS + 10L,
                 TimeUnit.MILLISECONDS);
         runUntilIdle();
-        verify(mMediaSession, times(1)).resume();
+        verify(mMediaSession, times(1)).resume(SuspendType.SYSTEM);
     }
 
     /**
@@ -207,7 +207,7 @@
 
         // Stashing paused video should do nothing.
         mController.onStashReported(true);
-        verify(mMediaSession, times(0)).suspend(SuspendType.UI);
+        verify(mMediaSession, times(0)).suspend(SuspendType.SYSTEM);
 
         // Un-stash should also do nothing.
         mController.onStashReported(false);
@@ -215,7 +215,7 @@
                 FullscreenVideoPictureInPictureController.UNSTASH_DELAY_MILLIS + 10L,
                 TimeUnit.MILLISECONDS);
         runUntilIdle();
-        verify(mMediaSession, times(0)).resume();
+        verify(mMediaSession, times(0)).resume(SuspendType.SYSTEM);
     }
 
     /** If video starts playing during a normal stash, unstash should no-op. */
@@ -226,7 +226,7 @@
         // Stash normally.
         mWebContentsObserverCaptor.getValue().mediaStartedPlaying(0, true, true);
         mController.onStashReported(true);
-        verify(mMediaSession, times(1)).suspend(SuspendType.UI);
+        verify(mMediaSession, times(1)).suspend(SuspendType.SYSTEM);
         mWebContentsObserverCaptor.getValue().mediaStoppedPlaying(0);
 
         // Restart playback while still stashed.
@@ -238,7 +238,7 @@
                 FullscreenVideoPictureInPictureController.UNSTASH_DELAY_MILLIS + 10L,
                 TimeUnit.MILLISECONDS);
         runUntilIdle();
-        verify(mMediaSession, times(0)).resume();
+        verify(mMediaSession, times(0)).resume(SuspendType.SYSTEM);
     }
 
     @Test
@@ -254,7 +254,7 @@
         mController.onResume();
         verify(mActivity, times(0)).moveTaskToBack(true);
         // The media should be paused, though, just as if pip had closed.
-        verify(mMediaSession, times(1)).suspend(SuspendType.UI);
+        verify(mMediaSession, times(1)).suspend(SuspendType.SYSTEM);
 
         // When the device is unlocked, we will get `onStart`.  This should cause pip to close
         // because it's still deferred from the `onResume` call, above.
diff --git a/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java b/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java
index 95d1e9ed..eaf3ce8 100644
--- a/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java
+++ b/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java
@@ -163,7 +163,7 @@
 
                     if (mMediaSessionObserver.getMediaSession() == null) return;
 
-                    mMediaSessionObserver.getMediaSession().resume();
+                    mMediaSessionObserver.getMediaSession().resume(SuspendType.UI);
                 }
 
                 @Override
diff --git a/content/browser/media/session/media_session_android.cc b/content/browser/media/session/media_session_android.cc
index 5aa7602..c15dff98 100644
--- a/content/browser/media/session/media_session_android.cc
+++ b/content/browser/media/session/media_session_android.cc
@@ -162,9 +162,11 @@
   }
 }
 
-void MediaSessionAndroid::Resume(JNIEnv* env) {
+void MediaSessionAndroid::Resume(
+    JNIEnv* env,
+    media_session::mojom::MediaSession::SuspendType suspend_type) {
   DCHECK(media_session_);
-  media_session_->Resume(MediaSession::SuspendType::kUI);
+  media_session_->Resume(suspend_type);
 }
 
 void MediaSessionAndroid::Suspend(
diff --git a/content/browser/media/session/media_session_android.h b/content/browser/media/session/media_session_android.h
index 0dfd959b1..0c93dff 100644
--- a/content/browser/media/session/media_session_android.h
+++ b/content/browser/media/session/media_session_android.h
@@ -53,7 +53,8 @@
       const std::optional<media_session::MediaPosition>& position) override;
 
   // MediaSession method wrappers.
-  void Resume(JNIEnv* env);
+  void Resume(JNIEnv* env,
+              media_session::mojom::MediaSession::SuspendType suspend_type);
   void Suspend(JNIEnv* env,
                media_session::mojom::MediaSession::SuspendType suspend_type);
   void Stop(JNIEnv* env);
diff --git a/content/public/android/java/src/org/chromium/content/browser/MediaSessionImpl.java b/content/public/android/java/src/org/chromium/content/browser/MediaSessionImpl.java
index 8bdfff2..36e5f92 100644
--- a/content/public/android/java/src/org/chromium/content/browser/MediaSessionImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/MediaSessionImpl.java
@@ -79,8 +79,8 @@
     }
 
     @Override
-    public void resume() {
-        MediaSessionImplJni.get().resume(mNativeMediaSessionAndroid);
+    public void resume(@SuspendType.EnumType int suspendType) {
+        MediaSessionImplJni.get().resume(mNativeMediaSessionAndroid, suspendType);
     }
 
     @Override
@@ -196,7 +196,9 @@
 
     @NativeMethods
     public interface Natives {
-        void resume(long nativeMediaSessionAndroid);
+        void resume(
+                long nativeMediaSessionAndroid,
+                @JniType("media_session::mojom::MediaSession::SuspendType") int suspendType);
 
         void suspend(
                 long nativeMediaSessionAndroid,
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/MediaSession.java b/content/public/android/java/src/org/chromium/content_public/browser/MediaSession.java
index 6af471b..d7ba9f7b 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/MediaSession.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/MediaSession.java
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.