Merge "Add createVirtualDisplay in DisplayManager for VirtualDeviceManager"

This commit is contained in:
TreeHugger Robot
2021-12-09 08:34:16 +00:00
committed by Android (Google) Code Review
8 changed files with 156 additions and 68 deletions

View File

@@ -30,6 +30,7 @@ import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.app.KeyguardManager;
import android.companion.virtual.IVirtualDevice;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Resources;
@@ -902,8 +903,16 @@ public final class DisplayManager {
@NonNull VirtualDisplayConfig virtualDisplayConfig,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler,
@Nullable Context windowContext) {
return mGlobal.createVirtualDisplay(mContext, projection, virtualDisplayConfig, callback,
handler, windowContext);
return mGlobal.createVirtualDisplay(mContext, projection, null /* virtualDevice */,
virtualDisplayConfig, callback, handler, windowContext);
}
/** @hide */
public VirtualDisplay createVirtualDisplay(@Nullable IVirtualDevice virtualDevice,
@NonNull VirtualDisplayConfig virtualDisplayConfig,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
return mGlobal.createVirtualDisplay(mContext, null /* projection */, virtualDevice,
virtualDisplayConfig, callback, handler, null);
}
/**

View File

@@ -24,6 +24,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PropertyInvalidatedCache;
import android.companion.virtual.IVirtualDevice;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.ParceledListSlice;
@@ -582,14 +583,14 @@ public final class DisplayManagerGlobal {
}
public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection,
@NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback,
Handler handler, @Nullable Context windowContext) {
IVirtualDevice virtualDevice, @NonNull VirtualDisplayConfig virtualDisplayConfig,
VirtualDisplay.Callback callback, Handler handler, @Nullable Context windowContext) {
VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler);
IMediaProjection projectionToken = projection != null ? projection.getProjection() : null;
int displayId;
try {
displayId = mDm.createVirtualDisplay(virtualDisplayConfig, callbackWrapper,
projectionToken, context.getPackageName());
projectionToken, virtualDevice, context.getPackageName());
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}

View File

@@ -20,7 +20,6 @@ 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;
@@ -380,31 +379,6 @@ 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}
*

View File

@@ -16,6 +16,7 @@
package android.hardware.display;
import android.companion.virtual.IVirtualDevice;
import android.content.pm.ParceledListSlice;
import android.graphics.Point;
import android.hardware.display.BrightnessConfiguration;
@@ -86,10 +87,10 @@ interface IDisplayManager {
void requestColorMode(int displayId, int colorMode);
// Requires CAPTURE_VIDEO_OUTPUT, CAPTURE_SECURE_VIDEO_OUTPUT, or an appropriate
// MediaProjection token for certain combinations of flags.
// MediaProjection token or VirtualDevice for certain combinations of flags.
int createVirtualDisplay(in VirtualDisplayConfig virtualDisplayConfig,
in IVirtualDisplayCallback callback, in IMediaProjection projectionToken,
String packageName);
in IVirtualDevice virtualDevice, String packageName);
// No permissions required, but must be same Uid as the creator.
void resizeVirtualDisplay(in IVirtualDisplayCallback token,

View File

@@ -31,6 +31,7 @@ import android.os.RemoteException;
import android.util.ExceptionUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.window.DisplayWindowPolicyController;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.DumpUtils;
@@ -38,11 +39,11 @@ import com.android.server.SystemService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/** @hide */
@SuppressLint("LongLogTag")
public class VirtualDeviceManagerService extends SystemService {
@@ -84,6 +85,15 @@ public class VirtualDeviceManagerService extends SystemService {
publishLocalService(VirtualDeviceManagerInternal.class, new LocalService());
}
@GuardedBy("mVirtualDeviceManagerLock")
private boolean isValidVirtualDeviceLocked(IVirtualDevice virtualDevice) {
try {
return mVirtualDevices.contains(virtualDevice.getAssociationId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
@Override
public void onUserStarting(@NonNull TargetUser user) {
super.onUserStarting(user);
@@ -121,6 +131,7 @@ public class VirtualDeviceManagerService extends SystemService {
private final AssociationInfo mAssociationInfo;
private final int mOwnerUid;
private final ArrayList<Integer> mDisplayIds = new ArrayList<>();
private VirtualDeviceImpl(int ownerUid, IBinder token, AssociationInfo associationInfo) {
mOwnerUid = ownerUid;
@@ -149,6 +160,24 @@ public class VirtualDeviceManagerService extends SystemService {
public void binderDied() {
close();
}
DisplayWindowPolicyController onVirtualDisplayCreatedLocked(int displayId) {
if (mDisplayIds.contains(displayId)) {
throw new IllegalStateException(
"Virtual device already have a virtual display with ID " + displayId);
}
mDisplayIds.add(displayId);
// TODO(b/201712607): Return the corresponding DisplayWindowPolicyController.
return null;
}
void onVirtualDisplayRemovedLocked(int displayId) {
if (!mDisplayIds.contains(displayId)) {
throw new IllegalStateException(
"Virtual device doesn't have a virtual display with ID " + displayId);
}
mDisplayIds.remove(displayId);
}
}
class VirtualDeviceManagerImpl extends IVirtualDeviceManager.Stub {
@@ -229,6 +258,28 @@ public class VirtualDeviceManagerService extends SystemService {
private final class LocalService extends VirtualDeviceManagerInternal {
@Override
public boolean isValidVirtualDevice(IVirtualDevice virtualDevice) {
synchronized (mVirtualDeviceManagerLock) {
return isValidVirtualDeviceLocked(virtualDevice);
}
}
@Override
public DisplayWindowPolicyController onVirtualDisplayCreated(IVirtualDevice virtualDevice,
int displayId) {
synchronized (mVirtualDeviceManagerLock) {
return ((VirtualDeviceImpl) virtualDevice).onVirtualDisplayCreatedLocked(displayId);
}
}
@Override
public void onVirtualDisplayRemoved(IVirtualDevice virtualDevice, int displayId) {
synchronized (mVirtualDeviceManagerLock) {
((VirtualDeviceImpl) virtualDevice).onVirtualDisplayRemovedLocked(displayId);
}
}
@Override
public boolean isAppOwnerOfAnyVirtualDevice(int uid) {
synchronized (mVirtualDeviceManagerLock) {

View File

@@ -16,11 +16,39 @@
package com.android.server.companion.virtual;
import android.companion.virtual.IVirtualDevice;
import android.window.DisplayWindowPolicyController;
/**
* Virtual device manager local service interface.
* Only for use within system server.
*/
public abstract class VirtualDeviceManagerInternal {
/**
* Validate the virtual device.
*/
public abstract boolean isValidVirtualDevice(IVirtualDevice virtualDevice);
/**
* Notify a virtual display is created.
*
* @param virtualDevice The virtual device where the virtual display located.
* @param displayId The display id of the created virtual display.
*
* @return The {@link DisplayWindowPolicyController} of the virtual device.
*/
public abstract DisplayWindowPolicyController onVirtualDisplayCreated(
IVirtualDevice virtualDevice, int displayId);
/**
* Notify a virtual display is removed.
*
* @param virtualDevice The virtual device where the virtual display located.
* @param displayId The display id of the removed virtual display.
*/
public abstract void onVirtualDisplayRemoved(IVirtualDevice virtualDevice, int displayId);
/**
* Returns true if the given {@code uid} is the owner of any virtual devices that are
* currently active.

View File

@@ -42,6 +42,7 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.compat.CompatChanges;
import android.companion.virtual.IVirtualDevice;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.Context;
@@ -126,6 +127,7 @@ import com.android.server.DisplayThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.UiThread;
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
import com.android.server.display.DisplayDeviceConfig.SensorData;
import com.android.server.display.utils.SensorUtils;
import com.android.server.wm.SurfaceAnimationThread;
@@ -244,9 +246,12 @@ public final class DisplayManagerService extends SystemService {
public final SparseArray<CallbackRecord> mCallbacks =
new SparseArray<CallbackRecord>();
/** All {@link DisplayWindowPolicyController}s indexed by {@link DisplayInfo#displayId}. */
final SparseArray<DisplayWindowPolicyController> mDisplayWindowPolicyController =
new SparseArray<>();
/**
* All {@link IVirtualDevice} and {@link DisplayWindowPolicyController}s indexed by
* {@link DisplayInfo#displayId}.
*/
final SparseArray<Pair<IVirtualDevice, DisplayWindowPolicyController>>
mDisplayWindowPolicyControllers = new SparseArray<>();
// List of all currently registered display adapters.
private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();
@@ -1180,8 +1185,8 @@ public final class DisplayManagerService extends SystemService {
}
private int createVirtualDisplayInternal(VirtualDisplayConfig virtualDisplayConfig,
IVirtualDisplayCallback callback, IMediaProjection projection, String packageName,
DisplayWindowPolicyController controller) {
IVirtualDisplayCallback callback, IMediaProjection projection,
IVirtualDevice virtualDevice, String packageName) {
final int callingUid = Binder.getCallingUid();
if (!validatePackageName(callingUid, packageName)) {
throw new SecurityException("packageName must match the calling uid");
@@ -1226,6 +1231,14 @@ public final class DisplayManagerService extends SystemService {
}
}
if (virtualDevice != null) {
final VirtualDeviceManagerInternal vdm =
getLocalService(VirtualDeviceManagerInternal.class);
if (!vdm.isValidVirtualDevice(virtualDevice)) {
throw new SecurityException("Invalid virtual device");
}
}
if (callingUid != Process.SYSTEM_UID
&& (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
if (!canProjectVideo(projection)) {
@@ -1306,8 +1319,8 @@ public final class DisplayManagerService extends SystemService {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
return createVirtualDisplayLocked(callback, projection, callingUid, packageName,
surface, flags, virtualDisplayConfig, controller);
return createVirtualDisplayLocked(callback, projection, virtualDevice, callingUid,
packageName, surface, flags, virtualDisplayConfig);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -1315,9 +1328,9 @@ public final class DisplayManagerService extends SystemService {
}
private int createVirtualDisplayLocked(IVirtualDisplayCallback callback,
IMediaProjection projection, int callingUid, String packageName, Surface surface,
int flags, VirtualDisplayConfig virtualDisplayConfig,
DisplayWindowPolicyController controller) {
IMediaProjection projection, IVirtualDevice virtualDevice,
int callingUid, String packageName, Surface surface,
int flags, VirtualDisplayConfig virtualDisplayConfig) {
if (mVirtualDisplayAdapter == null) {
Slog.w(TAG, "Rejecting request to create private virtual display "
+ "because the virtual display adapter is not available.");
@@ -1344,10 +1357,16 @@ public final class DisplayManagerService extends SystemService {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
if (display != null) {
if (controller != null) {
mDisplayWindowPolicyController.put(display.getDisplayIdLocked(), controller);
final int displayId = display.getDisplayIdLocked();
if (virtualDevice != null) {
final VirtualDeviceManagerInternal vdm =
getLocalService(VirtualDeviceManagerInternal.class);
final DisplayWindowPolicyController controller =
vdm.onVirtualDisplayCreated(virtualDevice, displayId);
mDisplayWindowPolicyControllers.put(displayId,
Pair.create(virtualDevice, controller));
}
return display.getDisplayIdLocked();
return displayId;
}
// Something weird happened and the logical display was not created.
@@ -1391,7 +1410,13 @@ public final class DisplayManagerService extends SystemService {
if (device != null) {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
if (display != null) {
mDisplayWindowPolicyController.delete(display.getDisplayIdLocked());
final int displayId = display.getDisplayIdLocked();
if (mDisplayWindowPolicyControllers.contains(displayId)) {
Pair<IVirtualDevice, DisplayWindowPolicyController> pair =
mDisplayWindowPolicyControllers.removeReturnOld(displayId);
getLocalService(VirtualDeviceManagerInternal.class)
.onVirtualDisplayRemoved(pair.first, displayId);
}
}
// TODO: multi-display - handle virtual displays the same as other display adapters.
mDisplayDeviceRepo.onDisplayDeviceEvent(device,
@@ -2345,13 +2370,13 @@ public final class DisplayManagerService extends SystemService {
pw.println();
mPersistentDataStore.dump(pw);
final int displayWindowPolicyControllerCount = mDisplayWindowPolicyController.size();
final int displayWindowPolicyControllerCount = mDisplayWindowPolicyControllers.size();
pw.println();
pw.println("Display Window Policy Controllers: size="
+ displayWindowPolicyControllerCount);
for (int i = 0; i < displayWindowPolicyControllerCount; i++) {
pw.print("Display " + mDisplayWindowPolicyController.keyAt(i) + ":");
mDisplayWindowPolicyController.valueAt(i).dump(" ", pw);
pw.print("Display " + mDisplayWindowPolicyControllers.keyAt(i) + ":");
mDisplayWindowPolicyControllers.valueAt(i).second.dump(" ", pw);
}
}
pw.println();
@@ -2922,9 +2947,10 @@ public final class DisplayManagerService extends SystemService {
@Override // Binder call
public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
IVirtualDisplayCallback callback, IMediaProjection projection, String packageName) {
IVirtualDisplayCallback callback, IMediaProjection projection,
IVirtualDevice virtualDeviceToken, String packageName) {
return createVirtualDisplayInternal(virtualDisplayConfig, callback, projection,
packageName, null /* controller */);
virtualDeviceToken, packageName);
}
@Override // Binder call
@@ -3689,18 +3715,13 @@ 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) {
return mDisplayWindowPolicyController.get(displayId);
if (mDisplayWindowPolicyControllers.contains(displayId)) {
return mDisplayWindowPolicyControllers.get(displayId).second;
}
return null;
}
}
}

View File

@@ -219,7 +219,7 @@ public class DisplayManagerServiceTest {
builder.setUniqueId(uniqueId);
builder.setFlags(flags);
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
null /* projection */, PACKAGE_NAME);
null /* projection */, null /* virtualDeviceToken */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -341,7 +341,7 @@ public class DisplayManagerServiceTest {
builder.setFlags(flags);
builder.setUniqueId(uniqueId);
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
null /* projection */, PACKAGE_NAME);
null /* projection */, null /* virtualDeviceToken */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -580,7 +580,8 @@ public class DisplayManagerServiceTest {
VIRTUAL_DISPLAY_NAME, width, height, dpi);
builder.setUniqueId(uniqueId);
final int firstDisplayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
mMockAppToken /* callback */, null /* projection */, null /* virtualDeviceToken */,
PACKAGE_NAME);
// The second virtual display requests to mirror the first virtual display.
final String uniqueId2 = "uniqueId --- displayIdToMirrorTest #2";
@@ -590,7 +591,8 @@ public class DisplayManagerServiceTest {
builder2.setUniqueId(uniqueId2);
builder2.setDisplayIdToMirror(firstDisplayId);
final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(),
mMockAppToken2 /* callback */, null /* projection */, PACKAGE_NAME);
mMockAppToken2 /* callback */, null /* projection */,
null /* virtualDeviceToken */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler
@@ -628,7 +630,8 @@ public class DisplayManagerServiceTest {
builder.setSurface(surface);
builder.setUniqueId(uniqueId);
final int displayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
mMockAppToken /* callback */, null /* projection */, null /* virtualDeviceToken */,
PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -1108,7 +1111,7 @@ public class DisplayManagerServiceTest {
builder.setUniqueId(uniqueId);
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
null /* projection */, PACKAGE_NAME);
null /* projection */, null /* virtualDeviceToken */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);