From c6f10b42d9d905da3a8e41033b1233b9212274e8 Mon Sep 17 00:00:00 2001 From: Chavi Weingarten Date: Fri, 23 Sep 2022 18:14:49 +0000 Subject: [PATCH] Move MediaProjectionGlobal API to DisplayManager Add a static method in DisplayManager that allows the caller to create a VirtualDisplay without having an instance of DisplayManager (which requires a context). This can only be used from a process that has the CAPTURE_VIDEO_OUTPUT permission. Also added RequiresPermission(CAPTURE_VIDEO_OUTPUT) annotation for the new API. Test: DisplayManagerTest Bug: 247776252 Change-Id: I1eb94ab1063d89860cdfb2a58d4653d9a77eec98 --- core/api/system-current.txt | 10 +- .../hardware/display/DisplayManager.java | 59 +++++++++ core/java/android/view/SurfaceControl.java | 5 +- .../projection/MediaProjectionGlobal.java | 120 ------------------ 4 files changed, 62 insertions(+), 132 deletions(-) delete mode 100644 media/java/android/media/projection/MediaProjectionGlobal.java diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 7dcfab4b55032..f221eca453377 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -3951,6 +3951,7 @@ package android.hardware.display { } public final class DisplayManager { + method @Nullable @RequiresPermission("android.permission.CAPTURE_VIDEO_OUTPUT") public static android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface); method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_LIGHT_STATS) public java.util.List getAmbientBrightnessStats(); method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration(); method @Nullable @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getBrightnessConfigurationForDisplay(@NonNull String); @@ -6672,15 +6673,6 @@ package android.media.musicrecognition { } -package android.media.projection { - - public class MediaProjectionGlobal { - method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface); - method @NonNull public static android.media.projection.MediaProjectionGlobal getInstance(); - } - -} - package android.media.session { public final class MediaSessionManager { diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 8bc11cbc61de9..4e410b11e36e1 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -33,6 +33,7 @@ import android.app.KeyguardManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.content.pm.IPackageManager; import android.content.res.Resources; import android.graphics.Point; import android.media.projection.MediaProjection; @@ -40,6 +41,9 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.Looper; +import android.os.Process; +import android.os.RemoteException; +import android.os.ServiceManager; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; @@ -1304,6 +1308,61 @@ private int toMatchContentFrameRateSetting(@SwitchingType int switchingType) { } } + /** + * Creates a VirtualDisplay that will mirror the content of displayIdToMirror + * @param name The name for the virtual display + * @param width The initial width for the virtual display + * @param height The initial height for the virtual display + * @param displayIdToMirror The displayId that will be mirrored into the virtual display. + * @return VirtualDisplay that can be used to update properties. + * + * @hide + */ + @RequiresPermission(Manifest.permission.CAPTURE_VIDEO_OUTPUT) + @Nullable + @SystemApi + public static VirtualDisplay createVirtualDisplay(@NonNull String name, int width, int height, + int displayIdToMirror, @Nullable Surface surface) { + IDisplayManager sDm = IDisplayManager.Stub.asInterface( + ServiceManager.getService(Context.DISPLAY_SERVICE)); + IPackageManager sPackageManager = IPackageManager.Stub.asInterface( + ServiceManager.getService("package")); + + // Density doesn't matter since this virtual display is only used for mirroring. + VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width, + height, 1 /* densityDpi */) + .setFlags(VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) + .setDisplayIdToMirror(displayIdToMirror); + if (surface != null) { + builder.setSurface(surface); + } + VirtualDisplayConfig virtualDisplayConfig = builder.build(); + + String[] packages; + try { + packages = sPackageManager.getPackagesForUid(Process.myUid()); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + + // Just use the first one since it just needs to match the package when looking it up by + // calling UID in system server. + // The call may come from a rooted device, in that case the requesting uid will be root so + // it will not have any package name + String packageName = packages == null ? null : packages[0]; + DisplayManagerGlobal.VirtualDisplayCallback + callbackWrapper = new DisplayManagerGlobal.VirtualDisplayCallback(null, null); + int displayId; + try { + displayId = sDm.createVirtualDisplay(virtualDisplayConfig, callbackWrapper, null, + packageName); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + return DisplayManagerGlobal.getInstance().createVirtualDisplayWrapper(virtualDisplayConfig, + null, callbackWrapper, displayId); + } + /** * Listens for changes in available display devices. */ diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 9322bf6deefba..1b18783901908 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -57,7 +57,6 @@ import android.hardware.display.IVirtualDisplayCallback; import android.hardware.display.VirtualDisplay; import android.hardware.graphics.common.DisplayDecorationSupport; -import android.media.projection.MediaProjectionGlobal; import android.opengl.EGLDisplay; import android.opengl.EGLSync; import android.os.Build; @@ -2017,8 +2016,8 @@ public static IBinder createDisplay(String name, boolean secure) { } // We don't have a size yet so pass in 1 for width and height since 0 is invalid - VirtualDisplay vd = MediaProjectionGlobal.getInstance().createVirtualDisplay(name, - 1 /* width */, 1 /* height */, INVALID_DISPLAY, null /* Surface */); + VirtualDisplay vd = DisplayManager.createVirtualDisplay(name, 1 /* width */, 1 /* height */, + INVALID_DISPLAY, null /* Surface */); return vd == null ? null : vd.getToken().asBinder(); } diff --git a/media/java/android/media/projection/MediaProjectionGlobal.java b/media/java/android/media/projection/MediaProjectionGlobal.java deleted file mode 100644 index 4374a052dad28..0000000000000 --- a/media/java/android/media/projection/MediaProjectionGlobal.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.media.projection; - -import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.content.Context; -import android.content.pm.IPackageManager; -import android.hardware.display.DisplayManagerGlobal; -import android.hardware.display.IDisplayManager; -import android.hardware.display.VirtualDisplay; -import android.hardware.display.VirtualDisplayConfig; -import android.os.IBinder; -import android.os.Process; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.view.Surface; - -/** - * This is a helper for MediaProjection when requests are made from outside an application. This - * should only be used by processes running as shell as a way to capture recordings without being - * an application. The requests will fail if coming from any process that's not Shell. - * @hide - */ -@SystemApi -public class MediaProjectionGlobal { - private static final Object sLock = new Object(); - private static MediaProjectionGlobal sInstance; - - /** - * @return The instance of {@link MediaProjectionGlobal} - */ - @NonNull - public static MediaProjectionGlobal getInstance() { - synchronized (sLock) { - if (sInstance == null) { - final IBinder displayBinder = ServiceManager.getService(Context.DISPLAY_SERVICE); - final IBinder packageBinder = ServiceManager.getService("package"); - if (displayBinder != null && packageBinder != null) { - sInstance = new MediaProjectionGlobal( - IDisplayManager.Stub.asInterface(displayBinder), - IPackageManager.Stub.asInterface(packageBinder)); - } - } - return sInstance; - } - } - - private final IDisplayManager mDm; - private final IPackageManager mPackageManager; - - private MediaProjectionGlobal(IDisplayManager dm, IPackageManager packageManager) { - mDm = dm; - mPackageManager = packageManager; - } - - /** - * Creates a VirtualDisplay that will mirror the content of displayIdToMirror - * @param name The name for the virtual display - * @param width The initial width for the virtual display - * @param height The initial height for the virtual display - * @param displayIdToMirror The displayId that will be mirrored into the virtual display. - * @return VirtualDisplay that can be used to update properties. - */ - @Nullable - public VirtualDisplay createVirtualDisplay(@NonNull String name, int width, int height, - int displayIdToMirror, @Nullable Surface surface) { - - // Density doesn't matter since this virtual display is only used for mirroring. - VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width, - height, 1 /* densityDpi */) - .setFlags(VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) - .setDisplayIdToMirror(displayIdToMirror); - if (surface != null) { - builder.setSurface(surface); - } - VirtualDisplayConfig virtualDisplayConfig = builder.build(); - - String[] packages; - try { - packages = mPackageManager.getPackagesForUid(Process.myUid()); - } catch (RemoteException ex) { - throw ex.rethrowFromSystemServer(); - } - - // Just use the first one since it just needs to match the package when looking it up by - // calling UID in system server. - // The call may come from a rooted device, in that case the requesting uid will be root so - // it will not have any package name - String packageName = packages == null ? null : packages[0]; - DisplayManagerGlobal.VirtualDisplayCallback - callbackWrapper = new DisplayManagerGlobal.VirtualDisplayCallback(null, null); - int displayId; - try { - displayId = mDm.createVirtualDisplay(virtualDisplayConfig, callbackWrapper, null, - packageName); - } catch (RemoteException ex) { - throw ex.rethrowFromSystemServer(); - } - return DisplayManagerGlobal.getInstance().createVirtualDisplayWrapper(virtualDisplayConfig, - null, callbackWrapper, displayId); - } -}