diff options
8 files changed, 71 insertions, 30 deletions
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index c83869c9ee68..fb562d8e97db 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -32,7 +32,6 @@ import android.graphics.Region; import android.os.Bundle; import android.os.IRemoteCallback; import android.os.ParcelFileDescriptor; -import android.view.ContentRecordingSession; import android.view.DisplayCutout; import android.view.DisplayInfo; import android.view.IAppTransitionAnimationSpecsFuture; @@ -874,17 +873,6 @@ interface IWindowManager void detachWindowContextFromWindowContainer(IBinder clientToken); /** - * Updates the content recording session. If a different session is already in progress, then - * the pre-existing session is stopped, and the new incoming session takes over. - * - * The DisplayContent for the new session will begin recording when - * {@link RootWindowContainer#onDisplayChanged} is invoked for the new {@link VirtualDisplay}. - * - * @param incomingSession the nullable incoming content recording session - */ - void setContentRecordingSession(in ContentRecordingSession incomingSession); - - /** * Registers a listener, which is to be called whenever cross-window blur is enabled/disabled. * * @param listener the listener to be registered diff --git a/media/java/android/media/projection/IMediaProjectionManager.aidl b/media/java/android/media/projection/IMediaProjectionManager.aidl index d190fcec6c8c..1d58a409718d 100644 --- a/media/java/android/media/projection/IMediaProjectionManager.aidl +++ b/media/java/android/media/projection/IMediaProjectionManager.aidl @@ -21,6 +21,7 @@ import android.media.projection.IMediaProjectionCallback; import android.media.projection.IMediaProjectionWatcherCallback; import android.media.projection.MediaProjectionInfo; import android.os.IBinder; +import android.view.ContentRecordingSession; /** {@hide} */ interface IMediaProjectionManager { @@ -33,4 +34,15 @@ interface IMediaProjectionManager { void stopActiveProjection(); void addCallback(IMediaProjectionWatcherCallback callback); void removeCallback(IMediaProjectionWatcherCallback callback); + + /** + * Updates the content recording session. If a different session is already in progress, then + * the pre-existing session is stopped, and the new incoming session takes over. Only updates + * the session if the given projection is valid. + * + * @param incomingSession the nullable incoming content recording session + * @param projection the non-null projection the session describes + */ + void setContentRecordingSession(in ContentRecordingSession incomingSession, + in IMediaProjection projection); } diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java index b5f95938f845..ba7bf3f5f5d3 100644 --- a/media/java/android/media/projection/MediaProjection.java +++ b/media/java/android/media/projection/MediaProjection.java @@ -26,12 +26,11 @@ import android.hardware.display.VirtualDisplay; import android.hardware.display.VirtualDisplayConfig; import android.os.Handler; import android.os.RemoteException; +import android.os.ServiceManager; import android.util.ArrayMap; import android.util.Log; import android.view.ContentRecordingSession; -import android.view.IWindowManager; import android.view.Surface; -import android.view.WindowManagerGlobal; import android.window.WindowContainerToken; import java.util.Map; @@ -53,6 +52,7 @@ public final class MediaProjection { private final IMediaProjection mImpl; private final Context mContext; private final Map<Callback, CallbackRecord> mCallbacks; + @Nullable private IMediaProjectionManager mProjectionService = null; /** @hide */ public MediaProjection(Context context, IMediaProjection impl) { @@ -172,7 +172,6 @@ public final class MediaProjection { @NonNull VirtualDisplayConfig.Builder virtualDisplayConfig, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) { try { - final IWindowManager wmService = WindowManagerGlobal.getWindowManagerService(); final WindowContainerToken taskWindowContainerToken = mImpl.getTaskRecordingWindowContainerToken(); Context windowContext = null; @@ -199,7 +198,7 @@ public final class MediaProjection { } session.setDisplayId(virtualDisplay.getDisplay().getDisplayId()); // Successfully set up, so save the current session details. - wmService.setContentRecordingSession(session); + getProjectionService().setContentRecordingSession(session, mImpl); return virtualDisplay; } catch (RemoteException e) { // Can not capture if WMS is not accessible, so bail out. @@ -207,6 +206,14 @@ public final class MediaProjection { } } + private IMediaProjectionManager getProjectionService() { + if (mProjectionService == null) { + mProjectionService = IMediaProjectionManager.Stub.asInterface( + ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE)); + } + return mProjectionService; + } + /** * Stops projection. */ diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java index 1937852fa333..098e8f74749c 100644 --- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java +++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java @@ -45,14 +45,15 @@ import android.os.RemoteException; import android.os.UserHandle; import android.util.ArrayMap; import android.util.Slog; +import android.view.ContentRecordingSession; import android.window.WindowContainerToken; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.server.LocalServices; import com.android.server.SystemService; -import com.android.server.SystemService.TargetUser; import com.android.server.Watchdog; +import com.android.server.wm.WindowManagerInternal; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -381,6 +382,27 @@ public final class MediaProjectionManagerService extends SystemService } } + /** + * Updates the current content mirroring session. + */ + @Override + public void setContentRecordingSession(@Nullable ContentRecordingSession incomingSession, + @NonNull IMediaProjection projection) { + final long origId = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + if (!isValidMediaProjection(projection)) { + throw new SecurityException("Invalid media projection"); + } + LocalServices.getService( + WindowManagerInternal.class).setContentRecordingSession( + incomingSession); + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + @Override // Binder call public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java index 87523f44d4b6..5d2d5826f227 100644 --- a/services/core/java/com/android/server/wm/ContentRecorder.java +++ b/services/core/java/com/android/server/wm/ContentRecorder.java @@ -207,7 +207,8 @@ final class ContentRecorder { // Update the cached session state first, since updating the service will result in always // returning to this instance to update recording state. mContentRecordingSession = null; - mDisplayContent.mWmService.setContentRecordingSession(null); + mDisplayContent.mWmService.mContentRecordingController.setContentRecordingSessionLocked( + null, mDisplayContent.mWmService); } /** diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index c0d7d1362ac3..9eee7ba871a2 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -30,6 +30,7 @@ import android.hardware.display.DisplayManagerInternal; import android.os.Bundle; import android.os.IBinder; import android.util.Pair; +import android.view.ContentRecordingSession; import android.view.Display; import android.view.IInputFilter; import android.view.IRemoteAnimationFinishedCallback; @@ -869,4 +870,16 @@ public abstract class WindowManagerInternal { */ public abstract boolean isPointInsideWindow( @NonNull IBinder windowToken, int displayId, float displayX, float displayY); + + /** + * Updates the content recording session. If a different session is already in progress, then + * the pre-existing session is stopped, and the new incoming session takes over. + * + * The DisplayContent for the new session will begin recording when + * {@link RootWindowContainer#onDisplayChanged} is invoked for the new {@link VirtualDisplay}. + * Must be invoked for a valid MediaProjection session. + * + * @param incomingSession the nullable incoming content recording session + */ + public abstract void setContentRecordingSession(ContentRecordingSession incomingSession); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 7a5480401de8..902218621cd0 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2956,16 +2956,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - /** - * Updates the current content mirroring session. - */ - @Override - public void setContentRecordingSession(@Nullable ContentRecordingSession incomingSession) { - synchronized (mGlobalLock) { - mContentRecordingController.setContentRecordingSessionLocked(incomingSession, this); - } - } - // TODO(multi-display): remove when no default display use case. void prepareAppTransitionNone() { if (!checkCallingPermission(MANAGE_APP_TOKENS, "prepareAppTransition()")) { @@ -8242,6 +8232,14 @@ public class WindowManagerService extends IWindowManager.Stub return w.getBounds().contains((int) displayX, (int) displayY); } } + + @Override + public void setContentRecordingSession(@Nullable ContentRecordingSession incomingSession) { + synchronized (mGlobalLock) { + mContentRecordingController.setContentRecordingSessionLocked(incomingSession, + WindowManagerService.this); + } + } } void registerAppFreezeListener(AppFreezeListener listener) { diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index c5f785ea7680..32f3bfe5166c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -2441,7 +2441,7 @@ public class DisplayContentTests extends WindowTestsBase { ContentRecordingSession session = ContentRecordingSession.createDisplaySession( tokenToMirror); session.setDisplayId(displayId); - mWm.setContentRecordingSession(session); + mWm.mContentRecordingController.setContentRecordingSessionLocked(session, mWm); actualDC.updateRecording(); // THEN mirroring is not started, since a null surface indicates the VirtualDisplay is off. @@ -2470,7 +2470,7 @@ public class DisplayContentTests extends WindowTestsBase { ContentRecordingSession session = ContentRecordingSession.createDisplaySession( tokenToMirror); session.setDisplayId(displayId); - mWm.setContentRecordingSession(session); + mWm.mContentRecordingController.setContentRecordingSessionLocked(session, mWm); mWm.mRoot.onDisplayAdded(displayId); // WHEN getting the DisplayContent for the new virtual display. |