Adding API for creating virtual display with DWPC in system_server
Bug: 201712607 Test: manual Change-Id: Idc712c654c59cb38e023a81994a3acf8c5a0b859
This commit is contained in:
@@ -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;
|
||||
@@ -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}
|
||||
*
|
||||
|
||||
@@ -1120,50 +1120,211 @@ 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.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
|
||||
callback, projection, callingUid, packageName, surface, flags,
|
||||
virtualDisplayConfig);
|
||||
if (device == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// DisplayDevice events are handled manually for Virtual Displays.
|
||||
// TODO: multi-display Fix this so that generic add/remove events are not handled in a
|
||||
// different code path for virtual displays. Currently this happens so that we can
|
||||
// return a valid display ID synchronously upon successful Virtual Display creation.
|
||||
// This code can run on any binder thread, while onDisplayDeviceAdded() callbacks are
|
||||
// called on the DisplayThread (which we don't want to wait for?).
|
||||
// One option would be to actually wait here on the binder thread
|
||||
// to be notified when the virtual display is created (or failed).
|
||||
mDisplayDeviceRepo.onDisplayDeviceEvent(device,
|
||||
DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED);
|
||||
|
||||
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
|
||||
if (display != null) {
|
||||
if (controller != null) {
|
||||
mDisplayWindowPolicyController.put(display.getDisplayIdLocked(), controller);
|
||||
}
|
||||
return display.getDisplayIdLocked();
|
||||
}
|
||||
|
||||
// Something weird happened and the logical display was not created.
|
||||
Slog.w(TAG, "Rejecting request to create virtual display "
|
||||
+ "because the logical display was not created.");
|
||||
mVirtualDisplayAdapter.releaseVirtualDisplayLocked(callback.asBinder());
|
||||
mDisplayDeviceRepo.onDisplayDeviceEvent(device,
|
||||
DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
|
||||
if (mVirtualDisplayAdapter == null) {
|
||||
Slog.w(TAG, "Rejecting request to create private virtual display "
|
||||
+ "because the virtual display adapter is not available.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
|
||||
callback, projection, callingUid, packageName, surface, flags,
|
||||
virtualDisplayConfig);
|
||||
if (device == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// DisplayDevice events are handled manually for Virtual Displays.
|
||||
// TODO: multi-display Fix this so that generic add/remove events are not handled in a
|
||||
// different code path for virtual displays. Currently this happens so that we can
|
||||
// return a valid display ID synchronously upon successful Virtual Display creation.
|
||||
// This code can run on any binder thread, while onDisplayDeviceAdded() callbacks are
|
||||
// called on the DisplayThread (which we don't want to wait for?).
|
||||
// One option would be to actually wait here on the binder thread
|
||||
// to be notified when the virtual display is created (or failed).
|
||||
mDisplayDeviceRepo.onDisplayDeviceEvent(device,
|
||||
DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED);
|
||||
|
||||
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
|
||||
if (display != null) {
|
||||
if (controller != null) {
|
||||
mDisplayWindowPolicyController.put(display.getDisplayIdLocked(), controller);
|
||||
}
|
||||
return display.getDisplayIdLocked();
|
||||
}
|
||||
|
||||
// Something weird happened and the logical display was not created.
|
||||
Slog.w(TAG, "Rejecting request to create virtual display "
|
||||
+ "because the logical display was not created.");
|
||||
mVirtualDisplayAdapter.releaseVirtualDisplayLocked(callback.asBinder());
|
||||
mDisplayDeviceRepo.onDisplayDeviceEvent(device,
|
||||
DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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) {
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user