Loading core/java/android/hardware/display/DisplayManagerInternal.java +26 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.Nullable; import android.graphics.Point; import android.hardware.SensorManager; import android.media.projection.IMediaProjection; import android.os.Handler; import android.os.IBinder; import android.os.PowerManager; Loading Loading @@ -379,6 +380,31 @@ public abstract class DisplayManagerInternal { */ public abstract void onEarlyInteractivityChange(boolean interactive); /** * A special API for creates a virtual display with a DisplayPolicyController in system_server. * <p> * If this method is called without original calling uid, the caller must enforce the * corresponding permissions according to the flags. * {@link android.Manifest.permission#CAPTURE_VIDEO_OUTPUT} * {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} * {@link android.Manifest.permission#ADD_TRUSTED_DISPLAY} * {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW} * </p> * * @param virtualDisplayConfig The arguments for the virtual display configuration. See * {@link VirtualDisplayConfig} for using it. * @param callback Callback to call when the virtual display's state changes, or null if none. * @param projection MediaProjection token. * @param packageName The package name of the app. * @param controller The DisplayWindowPolicyControl that can control what contents are * allowed to be displayed. * @return The newly created virtual display id , or {@link Display#INVALID_DISPLAY} if the * virtual display cannot be created. */ public abstract int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig, IVirtualDisplayCallback callback, IMediaProjection projection, String packageName, DisplayWindowPolicyController controller); /** * Get {@link DisplayWindowPolicyController} associated to the {@link DisplayInfo#displayId} * Loading services/core/java/com/android/server/display/DisplayManagerService.java +206 −199 Original line number Diff line number Diff line Loading @@ -1120,11 +1120,173 @@ public final class DisplayManagerService extends SystemService { } } private int createVirtualDisplayInternal(IVirtualDisplayCallback callback, private boolean validatePackageName(int uid, String packageName) { if (packageName != null) { String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); if (packageNames != null) { for (String n : packageNames) { if (n.equals(packageName)) { return true; } } } } return false; } private boolean canProjectVideo(IMediaProjection projection) { if (projection != null) { try { if (projection.canProjectVideo()) { return true; } } catch (RemoteException e) { Slog.e(TAG, "Unable to query projection service for permissions", e); } } if (checkCallingPermission(CAPTURE_VIDEO_OUTPUT, "canProjectVideo()")) { return true; } return canProjectSecureVideo(projection); } private boolean canProjectSecureVideo(IMediaProjection projection) { if (projection != null) { try { if (projection.canProjectSecureVideo()) { return true; } } catch (RemoteException e) { Slog.e(TAG, "Unable to query projection service for permissions", e); } } return checkCallingPermission(CAPTURE_SECURE_VIDEO_OUTPUT, "canProjectSecureVideo()"); } private boolean checkCallingPermission(String permission, String func) { if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) { return true; } final String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + " requires " + permission; Slog.w(TAG, msg); return false; } private int createVirtualDisplayInternal(VirtualDisplayConfig virtualDisplayConfig, IVirtualDisplayCallback callback, IMediaProjection projection, String packageName, DisplayWindowPolicyController controller) { final int callingUid = Binder.getCallingUid(); if (!validatePackageName(callingUid, packageName)) { throw new SecurityException("packageName must match the calling uid"); } if (callback == null) { throw new IllegalArgumentException("appToken must not be null"); } if (virtualDisplayConfig == null) { throw new IllegalArgumentException("virtualDisplayConfig must not be null"); } final Surface surface = virtualDisplayConfig.getSurface(); int flags = virtualDisplayConfig.getFlags(); if (surface != null && surface.isSingleBuffered()) { throw new IllegalArgumentException("Surface can't be single-buffered"); } if ((flags & VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) { flags |= VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; // Public displays can't be allowed to show content when locked. if ((flags & VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) { throw new IllegalArgumentException( "Public display must not be marked as SHOW_WHEN_LOCKED_INSECURE"); } } if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; } if ((flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; } if (projection != null) { try { if (!getProjectionService().isValidMediaProjection(projection)) { throw new SecurityException("Invalid media projection"); } flags = projection.applyVirtualDisplayFlags(flags); } catch (RemoteException e) { throw new SecurityException("unable to validate media projection or flags"); } } if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { if (!canProjectVideo(projection)) { throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or " + "CAPTURE_SECURE_VIDEO_OUTPUT permission, or an appropriate " + "MediaProjection token in order to create a screen sharing virtual " + "display."); } } if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) { if (!canProjectSecureVideo(projection)) { throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT " + "or an appropriate MediaProjection token to create a " + "secure virtual display."); } } if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) { if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) { EventLog.writeEvent(0x534e4554, "162627132", callingUid, "Attempt to create a trusted display without holding permission!"); throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to " + "create a trusted virtual display."); } } if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) { if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) { throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to " + "create a virtual display which is not in the default DisplayGroup."); } } if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; } // Sometimes users can have sensitive information in system decoration windows. An app // could create a virtual display with system decorations support and read the user info // from the surface. // We should only allow adding flag VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS // to trusted virtual displays. final int trustedDisplayWithSysDecorFlag = (VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS | VIRTUAL_DISPLAY_FLAG_TRUSTED); if ((flags & trustedDisplayWithSysDecorFlag) == VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS && !checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "createVirtualDisplay()")) { throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission"); } final long token = Binder.clearCallingIdentity(); try { synchronized (mSyncRoot) { return createVirtualDisplayLocked(callback, projection, callingUid, packageName, surface, flags, virtualDisplayConfig, controller); } } finally { Binder.restoreCallingIdentity(token); } } private int createVirtualDisplayLocked(IVirtualDisplayCallback callback, IMediaProjection projection, int callingUid, String packageName, Surface surface, int flags, VirtualDisplayConfig virtualDisplayConfig, DisplayWindowPolicyController controller) { synchronized (mSyncRoot) { if (mVirtualDisplayAdapter == null) { Slog.w(TAG, "Rejecting request to create private virtual display " + "because the virtual display adapter is not available."); Loading Loading @@ -1163,7 +1325,6 @@ public final class DisplayManagerService extends SystemService { mVirtualDisplayAdapter.releaseVirtualDisplayLocked(callback.asBinder()); mDisplayDeviceRepo.onDisplayDeviceEvent(device, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED); } return -1; } Loading Loading @@ -2726,116 +2887,8 @@ public final class DisplayManagerService extends SystemService { @Override // Binder call public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig, IVirtualDisplayCallback callback, IMediaProjection projection, String packageName) { return createVirtualDisplay(virtualDisplayConfig, callback, projection, packageName, null /* controller */); } public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig, IVirtualDisplayCallback callback, IMediaProjection projection, String packageName, DisplayWindowPolicyController controller) { final int callingUid = Binder.getCallingUid(); if (!validatePackageName(callingUid, packageName)) { throw new SecurityException("packageName must match the calling uid"); } if (callback == null) { throw new IllegalArgumentException("appToken must not be null"); } if (virtualDisplayConfig == null) { throw new IllegalArgumentException("virtualDisplayConfig must not be null"); } final Surface surface = virtualDisplayConfig.getSurface(); int flags = virtualDisplayConfig.getFlags(); if (surface != null && surface.isSingleBuffered()) { throw new IllegalArgumentException("Surface can't be single-buffered"); } if ((flags & VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) { flags |= VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; // Public displays can't be allowed to show content when locked. if ((flags & VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) { throw new IllegalArgumentException( "Public display must not be marked as SHOW_WHEN_LOCKED_INSECURE"); } } if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; } if ((flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; } if (projection != null) { try { if (!getProjectionService().isValidMediaProjection(projection)) { throw new SecurityException("Invalid media projection"); } flags = projection.applyVirtualDisplayFlags(flags); } catch (RemoteException e) { throw new SecurityException("unable to validate media projection or flags"); } } if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { if (!canProjectVideo(projection)) { throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or " + "CAPTURE_SECURE_VIDEO_OUTPUT permission, or an appropriate " + "MediaProjection token in order to create a screen sharing virtual " + "display."); } } if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) { if (!canProjectSecureVideo(projection)) { throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT " + "or an appropriate MediaProjection token to create a " + "secure virtual display."); } } if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) { if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) { EventLog.writeEvent(0x534e4554, "162627132", callingUid, "Attempt to create a trusted display without holding permission!"); throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to " + "create a trusted virtual display."); } } if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) { if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) { throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to " + "create a virtual display which is not in the default DisplayGroup."); } } if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; } // Sometimes users can have sensitive information in system decoration windows. An app // could create a virtual display with system decorations support and read the user info // from the surface. // We should only allow adding flag VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS // to trusted virtual displays. final int trustedDisplayWithSysDecorFlag = (VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS | VIRTUAL_DISPLAY_FLAG_TRUSTED); if ((flags & trustedDisplayWithSysDecorFlag) == VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS && !checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "createVirtualDisplay()")) { throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission"); } final long token = Binder.clearCallingIdentity(); try { return createVirtualDisplayInternal(callback, projection, callingUid, packageName, surface, flags, virtualDisplayConfig, controller); } finally { Binder.restoreCallingIdentity(token); } return createVirtualDisplayInternal(virtualDisplayConfig, callback, projection, packageName, null /* controller */); } @Override // Binder call Loading Loading @@ -3265,60 +3318,6 @@ public final class DisplayManagerService extends SystemService { Binder.restoreCallingIdentity(token); } } private boolean validatePackageName(int uid, String packageName) { if (packageName != null) { String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); if (packageNames != null) { for (String n : packageNames) { if (n.equals(packageName)) { return true; } } } } return false; } private boolean canProjectVideo(IMediaProjection projection) { if (projection != null) { try { if (projection.canProjectVideo()) { return true; } } catch (RemoteException e) { Slog.e(TAG, "Unable to query projection service for permissions", e); } } if (checkCallingPermission(CAPTURE_VIDEO_OUTPUT, "canProjectVideo()")) { return true; } return canProjectSecureVideo(projection); } private boolean canProjectSecureVideo(IMediaProjection projection) { if (projection != null) { try { if (projection.canProjectSecureVideo()){ return true; } } catch (RemoteException e) { Slog.e(TAG, "Unable to query projection service for permissions", e); } } return checkCallingPermission(CAPTURE_SECURE_VIDEO_OUTPUT, "canProjectSecureVideo()"); } private boolean checkCallingPermission(String permission, String func) { if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) { return true; } final String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + " requires " + permission; Slog.w(TAG, msg); return false; } } private static boolean isValidBrightness(float brightness) { Loading Loading @@ -3654,6 +3653,14 @@ public final class DisplayManagerService extends SystemService { mLogicalDisplayMapper.onEarlyInteractivityChange(interactive); } @Override public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig, IVirtualDisplayCallback callback, IMediaProjection projection, String packageName, DisplayWindowPolicyController controller) { return createVirtualDisplayInternal(virtualDisplayConfig, callback, projection, packageName, controller); } @Override public DisplayWindowPolicyController getDisplayWindowPolicyController(int displayId) { synchronized (mSyncRoot) { Loading Loading
core/java/android/hardware/display/DisplayManagerInternal.java +26 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.Nullable; import android.graphics.Point; import android.hardware.SensorManager; import android.media.projection.IMediaProjection; import android.os.Handler; import android.os.IBinder; import android.os.PowerManager; Loading Loading @@ -379,6 +380,31 @@ public abstract class DisplayManagerInternal { */ public abstract void onEarlyInteractivityChange(boolean interactive); /** * A special API for creates a virtual display with a DisplayPolicyController in system_server. * <p> * If this method is called without original calling uid, the caller must enforce the * corresponding permissions according to the flags. * {@link android.Manifest.permission#CAPTURE_VIDEO_OUTPUT} * {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} * {@link android.Manifest.permission#ADD_TRUSTED_DISPLAY} * {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW} * </p> * * @param virtualDisplayConfig The arguments for the virtual display configuration. See * {@link VirtualDisplayConfig} for using it. * @param callback Callback to call when the virtual display's state changes, or null if none. * @param projection MediaProjection token. * @param packageName The package name of the app. * @param controller The DisplayWindowPolicyControl that can control what contents are * allowed to be displayed. * @return The newly created virtual display id , or {@link Display#INVALID_DISPLAY} if the * virtual display cannot be created. */ public abstract int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig, IVirtualDisplayCallback callback, IMediaProjection projection, String packageName, DisplayWindowPolicyController controller); /** * Get {@link DisplayWindowPolicyController} associated to the {@link DisplayInfo#displayId} * Loading
services/core/java/com/android/server/display/DisplayManagerService.java +206 −199 Original line number Diff line number Diff line Loading @@ -1120,11 +1120,173 @@ public final class DisplayManagerService extends SystemService { } } private int createVirtualDisplayInternal(IVirtualDisplayCallback callback, private boolean validatePackageName(int uid, String packageName) { if (packageName != null) { String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); if (packageNames != null) { for (String n : packageNames) { if (n.equals(packageName)) { return true; } } } } return false; } private boolean canProjectVideo(IMediaProjection projection) { if (projection != null) { try { if (projection.canProjectVideo()) { return true; } } catch (RemoteException e) { Slog.e(TAG, "Unable to query projection service for permissions", e); } } if (checkCallingPermission(CAPTURE_VIDEO_OUTPUT, "canProjectVideo()")) { return true; } return canProjectSecureVideo(projection); } private boolean canProjectSecureVideo(IMediaProjection projection) { if (projection != null) { try { if (projection.canProjectSecureVideo()) { return true; } } catch (RemoteException e) { Slog.e(TAG, "Unable to query projection service for permissions", e); } } return checkCallingPermission(CAPTURE_SECURE_VIDEO_OUTPUT, "canProjectSecureVideo()"); } private boolean checkCallingPermission(String permission, String func) { if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) { return true; } final String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + " requires " + permission; Slog.w(TAG, msg); return false; } private int createVirtualDisplayInternal(VirtualDisplayConfig virtualDisplayConfig, IVirtualDisplayCallback callback, IMediaProjection projection, String packageName, DisplayWindowPolicyController controller) { final int callingUid = Binder.getCallingUid(); if (!validatePackageName(callingUid, packageName)) { throw new SecurityException("packageName must match the calling uid"); } if (callback == null) { throw new IllegalArgumentException("appToken must not be null"); } if (virtualDisplayConfig == null) { throw new IllegalArgumentException("virtualDisplayConfig must not be null"); } final Surface surface = virtualDisplayConfig.getSurface(); int flags = virtualDisplayConfig.getFlags(); if (surface != null && surface.isSingleBuffered()) { throw new IllegalArgumentException("Surface can't be single-buffered"); } if ((flags & VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) { flags |= VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; // Public displays can't be allowed to show content when locked. if ((flags & VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) { throw new IllegalArgumentException( "Public display must not be marked as SHOW_WHEN_LOCKED_INSECURE"); } } if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; } if ((flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; } if (projection != null) { try { if (!getProjectionService().isValidMediaProjection(projection)) { throw new SecurityException("Invalid media projection"); } flags = projection.applyVirtualDisplayFlags(flags); } catch (RemoteException e) { throw new SecurityException("unable to validate media projection or flags"); } } if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { if (!canProjectVideo(projection)) { throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or " + "CAPTURE_SECURE_VIDEO_OUTPUT permission, or an appropriate " + "MediaProjection token in order to create a screen sharing virtual " + "display."); } } if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) { if (!canProjectSecureVideo(projection)) { throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT " + "or an appropriate MediaProjection token to create a " + "secure virtual display."); } } if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) { if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) { EventLog.writeEvent(0x534e4554, "162627132", callingUid, "Attempt to create a trusted display without holding permission!"); throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to " + "create a trusted virtual display."); } } if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) { if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) { throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to " + "create a virtual display which is not in the default DisplayGroup."); } } if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; } // Sometimes users can have sensitive information in system decoration windows. An app // could create a virtual display with system decorations support and read the user info // from the surface. // We should only allow adding flag VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS // to trusted virtual displays. final int trustedDisplayWithSysDecorFlag = (VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS | VIRTUAL_DISPLAY_FLAG_TRUSTED); if ((flags & trustedDisplayWithSysDecorFlag) == VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS && !checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "createVirtualDisplay()")) { throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission"); } final long token = Binder.clearCallingIdentity(); try { synchronized (mSyncRoot) { return createVirtualDisplayLocked(callback, projection, callingUid, packageName, surface, flags, virtualDisplayConfig, controller); } } finally { Binder.restoreCallingIdentity(token); } } private int createVirtualDisplayLocked(IVirtualDisplayCallback callback, IMediaProjection projection, int callingUid, String packageName, Surface surface, int flags, VirtualDisplayConfig virtualDisplayConfig, DisplayWindowPolicyController controller) { synchronized (mSyncRoot) { if (mVirtualDisplayAdapter == null) { Slog.w(TAG, "Rejecting request to create private virtual display " + "because the virtual display adapter is not available."); Loading Loading @@ -1163,7 +1325,6 @@ public final class DisplayManagerService extends SystemService { mVirtualDisplayAdapter.releaseVirtualDisplayLocked(callback.asBinder()); mDisplayDeviceRepo.onDisplayDeviceEvent(device, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED); } return -1; } Loading Loading @@ -2726,116 +2887,8 @@ public final class DisplayManagerService extends SystemService { @Override // Binder call public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig, IVirtualDisplayCallback callback, IMediaProjection projection, String packageName) { return createVirtualDisplay(virtualDisplayConfig, callback, projection, packageName, null /* controller */); } public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig, IVirtualDisplayCallback callback, IMediaProjection projection, String packageName, DisplayWindowPolicyController controller) { final int callingUid = Binder.getCallingUid(); if (!validatePackageName(callingUid, packageName)) { throw new SecurityException("packageName must match the calling uid"); } if (callback == null) { throw new IllegalArgumentException("appToken must not be null"); } if (virtualDisplayConfig == null) { throw new IllegalArgumentException("virtualDisplayConfig must not be null"); } final Surface surface = virtualDisplayConfig.getSurface(); int flags = virtualDisplayConfig.getFlags(); if (surface != null && surface.isSingleBuffered()) { throw new IllegalArgumentException("Surface can't be single-buffered"); } if ((flags & VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) { flags |= VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; // Public displays can't be allowed to show content when locked. if ((flags & VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) { throw new IllegalArgumentException( "Public display must not be marked as SHOW_WHEN_LOCKED_INSECURE"); } } if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; } if ((flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; } if (projection != null) { try { if (!getProjectionService().isValidMediaProjection(projection)) { throw new SecurityException("Invalid media projection"); } flags = projection.applyVirtualDisplayFlags(flags); } catch (RemoteException e) { throw new SecurityException("unable to validate media projection or flags"); } } if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { if (!canProjectVideo(projection)) { throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or " + "CAPTURE_SECURE_VIDEO_OUTPUT permission, or an appropriate " + "MediaProjection token in order to create a screen sharing virtual " + "display."); } } if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) { if (!canProjectSecureVideo(projection)) { throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT " + "or an appropriate MediaProjection token to create a " + "secure virtual display."); } } if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) { if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) { EventLog.writeEvent(0x534e4554, "162627132", callingUid, "Attempt to create a trusted display without holding permission!"); throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to " + "create a trusted virtual display."); } } if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) { if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) { throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to " + "create a virtual display which is not in the default DisplayGroup."); } } if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; } // Sometimes users can have sensitive information in system decoration windows. An app // could create a virtual display with system decorations support and read the user info // from the surface. // We should only allow adding flag VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS // to trusted virtual displays. final int trustedDisplayWithSysDecorFlag = (VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS | VIRTUAL_DISPLAY_FLAG_TRUSTED); if ((flags & trustedDisplayWithSysDecorFlag) == VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS && !checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "createVirtualDisplay()")) { throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission"); } final long token = Binder.clearCallingIdentity(); try { return createVirtualDisplayInternal(callback, projection, callingUid, packageName, surface, flags, virtualDisplayConfig, controller); } finally { Binder.restoreCallingIdentity(token); } return createVirtualDisplayInternal(virtualDisplayConfig, callback, projection, packageName, null /* controller */); } @Override // Binder call Loading Loading @@ -3265,60 +3318,6 @@ public final class DisplayManagerService extends SystemService { Binder.restoreCallingIdentity(token); } } private boolean validatePackageName(int uid, String packageName) { if (packageName != null) { String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); if (packageNames != null) { for (String n : packageNames) { if (n.equals(packageName)) { return true; } } } } return false; } private boolean canProjectVideo(IMediaProjection projection) { if (projection != null) { try { if (projection.canProjectVideo()) { return true; } } catch (RemoteException e) { Slog.e(TAG, "Unable to query projection service for permissions", e); } } if (checkCallingPermission(CAPTURE_VIDEO_OUTPUT, "canProjectVideo()")) { return true; } return canProjectSecureVideo(projection); } private boolean canProjectSecureVideo(IMediaProjection projection) { if (projection != null) { try { if (projection.canProjectSecureVideo()){ return true; } } catch (RemoteException e) { Slog.e(TAG, "Unable to query projection service for permissions", e); } } return checkCallingPermission(CAPTURE_SECURE_VIDEO_OUTPUT, "canProjectSecureVideo()"); } private boolean checkCallingPermission(String permission, String func) { if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) { return true; } final String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + " requires " + permission; Slog.w(TAG, msg); return false; } } private static boolean isValidBrightness(float brightness) { Loading Loading @@ -3654,6 +3653,14 @@ public final class DisplayManagerService extends SystemService { mLogicalDisplayMapper.onEarlyInteractivityChange(interactive); } @Override public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig, IVirtualDisplayCallback callback, IMediaProjection projection, String packageName, DisplayWindowPolicyController controller) { return createVirtualDisplayInternal(virtualDisplayConfig, callback, projection, packageName, controller); } @Override public DisplayWindowPolicyController getDisplayWindowPolicyController(int displayId) { synchronized (mSyncRoot) { Loading