Merge "Prevent deadlocks during VirtualDisplay creation" into tm-dev am: fc6eb70e0e am: de2d849abd

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18246032

Change-Id: Ie72dc45b6f7f5e55876cf8798553712db36f6b58
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Antony Sargent
2022-05-30 00:59:09 +00:00
committed by Automerger Merge Worker
13 changed files with 248 additions and 152 deletions

View File

@@ -19,6 +19,8 @@ package android.companion.virtual;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDeviceActivityListener;
import android.companion.virtual.VirtualDeviceParams;
import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplayConfig;
/**
* Interface for communication between VirtualDeviceManager and VirtualDeviceManagerService.
@@ -42,4 +44,16 @@ interface IVirtualDeviceManager {
IVirtualDevice createVirtualDevice(
in IBinder token, String packageName, int associationId,
in VirtualDeviceParams params, in IVirtualDeviceActivityListener activityListener);
/**
* Creates a virtual display owned by a particular virtual device.
*
* @param virtualDisplayConfig The configuration used in creating the display
* @param callback A callback that receives display lifecycle events
* @param virtualDevice The device that will own this display
* @param packageName The package name of the calling app
*/
int createVirtualDisplay(in VirtualDisplayConfig virtualDisplayConfig,
in IVirtualDisplayCallback callback, in IVirtualDevice virtualDevice,
String packageName);
}

View File

@@ -33,6 +33,8 @@ import android.content.Context;
import android.graphics.Point;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.VirtualDisplayFlag;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplay;
import android.hardware.display.VirtualDisplayConfig;
import android.hardware.input.VirtualKeyboard;
@@ -65,7 +67,7 @@ import java.util.function.IntConsumer;
public final class VirtualDeviceManager {
private static final boolean DEBUG = false;
private static final String LOG_TAG = "VirtualDeviceManager";
private static final String TAG = "VirtualDeviceManager";
private static final int DEFAULT_VIRTUAL_DISPLAY_FLAGS =
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
@@ -150,6 +152,7 @@ public final class VirtualDeviceManager {
public static class VirtualDevice implements AutoCloseable {
private final Context mContext;
private final IVirtualDeviceManager mService;
private final IVirtualDevice mVirtualDevice;
private final ArrayMap<ActivityListener, ActivityListenerDelegate> mActivityListeners =
new ArrayMap<>();
@@ -189,6 +192,7 @@ public final class VirtualDeviceManager {
Context context,
int associationId,
VirtualDeviceParams params) throws RemoteException {
mService = service;
mContext = context.getApplicationContext();
mVirtualDevice = service.createVirtualDevice(
new Binder(),
@@ -274,18 +278,23 @@ public final class VirtualDeviceManager {
// TODO(b/205343547): Handle display groups properly instead of creating a new display
// group for every new virtual display created using this API.
// belongs to the same display group.
DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
// DisplayManager will call into VirtualDeviceManagerInternal to register the
// created displays.
return displayManager.createVirtualDisplay(
mVirtualDevice,
new VirtualDisplayConfig.Builder(
getVirtualDisplayName(), width, height, densityDpi)
.setSurface(surface)
.setFlags(getVirtualDisplayFlags(flags))
.build(),
callback,
executor);
VirtualDisplayConfig config = new VirtualDisplayConfig.Builder(
getVirtualDisplayName(), width, height, densityDpi)
.setSurface(surface)
.setFlags(getVirtualDisplayFlags(flags))
.build();
IVirtualDisplayCallback callbackWrapper =
new DisplayManagerGlobal.VirtualDisplayCallback(callback, executor);
final int displayId;
try {
displayId = mService.createVirtualDisplay(config, callbackWrapper, mVirtualDevice,
mContext.getPackageName());
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
DisplayManagerGlobal displayManager = DisplayManagerGlobal.getInstance();
return displayManager.createVirtualDisplayWrapper(config, mContext, callbackWrapper,
displayId);
}
/**

View File

@@ -31,7 +31,6 @@ 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;
@@ -971,17 +970,8 @@ public final class DisplayManager {
executor = new HandlerExecutor(
Handler.createAsync(handler != null ? handler.getLooper() : Looper.myLooper()));
}
return mGlobal.createVirtualDisplay(mContext, projection, null /* virtualDevice */,
virtualDisplayConfig, callback, executor, windowContext);
}
/** @hide */
public VirtualDisplay createVirtualDisplay(@Nullable IVirtualDevice virtualDevice,
@NonNull VirtualDisplayConfig virtualDisplayConfig,
@Nullable VirtualDisplay.Callback callback,
@Nullable Executor executor) {
return mGlobal.createVirtualDisplay(mContext, null /* projection */, virtualDevice,
virtualDisplayConfig, callback, executor, null);
return mGlobal.createVirtualDisplay(mContext, projection, virtualDisplayConfig, callback,
executor, windowContext);
}
/**

View File

@@ -24,7 +24,6 @@ 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;
@@ -586,18 +585,28 @@ public final class DisplayManagerGlobal {
}
public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection,
IVirtualDevice virtualDevice, @NonNull VirtualDisplayConfig virtualDisplayConfig,
VirtualDisplay.Callback callback, @Nullable Executor executor,
@Nullable Context windowContext) {
@NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback,
@Nullable Executor executor, @Nullable Context windowContext) {
VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, executor);
IMediaProjection projectionToken = projection != null ? projection.getProjection() : null;
int displayId;
try {
displayId = mDm.createVirtualDisplay(virtualDisplayConfig, callbackWrapper,
projectionToken, virtualDevice, context.getPackageName());
projectionToken, context.getPackageName());
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
return createVirtualDisplayWrapper(virtualDisplayConfig, windowContext, callbackWrapper,
displayId);
}
/**
* Create a VirtualDisplay wrapper object for a newly created virtual display ; to be called
* once the display has been created in system_server.
*/
@Nullable
public VirtualDisplay createVirtualDisplayWrapper(VirtualDisplayConfig virtualDisplayConfig,
Context windowContext, IVirtualDisplayCallback callbackWrapper, int displayId) {
if (displayId < 0) {
Log.e(TAG, "Could not create virtual display: " + virtualDisplayConfig.getName());
return null;
@@ -1050,7 +1059,10 @@ public final class DisplayManagerGlobal {
}
}
private final static class VirtualDisplayCallback extends IVirtualDisplayCallback.Stub {
/**
* Assists in dispatching VirtualDisplay lifecycle event callbacks on a given Executor.
*/
public static final class VirtualDisplayCallback extends IVirtualDisplayCallback.Stub {
@Nullable private final VirtualDisplay.Callback mCallback;
@Nullable private final Executor mExecutor;
@@ -1062,7 +1074,7 @@ public final class DisplayManagerGlobal {
* @param executor The executor to call the {@code callback} on. Must not be {@code null} if
* the callback is not {@code null}.
*/
VirtualDisplayCallback(VirtualDisplay.Callback callback, Executor executor) {
public VirtualDisplayCallback(VirtualDisplay.Callback callback, Executor executor) {
mCallback = callback;
mExecutor = mCallback != null ? Objects.requireNonNull(executor) : null;
}

View File

@@ -18,6 +18,7 @@ package android.hardware.display;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.companion.virtual.IVirtualDevice;
import android.graphics.Point;
import android.hardware.SensorManager;
import android.os.Handler;
@@ -59,6 +60,14 @@ public abstract class DisplayManagerInternal {
public abstract void initPowerManagement(DisplayPowerCallbacks callbacks,
Handler handler, SensorManager sensorManager);
/**
* Called by the VirtualDeviceManagerService to create a VirtualDisplay owned by a
* VirtualDevice.
*/
public abstract int createVirtualDisplay(VirtualDisplayConfig config,
IVirtualDisplayCallback callback, IVirtualDevice virtualDevice,
DisplayWindowPolicyController dwpc, String packageName);
/**
* Called by the power manager to request a new power state.
* <p>

View File

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

View File

@@ -48,7 +48,6 @@ import com.android.internal.app.BlockedAppStreamingActivity;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
/**
@@ -66,6 +65,14 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
void onRunningAppsChanged(ArraySet<Integer> runningUids);
}
/**
* For communicating when activities are blocked from running on the display by this policy
* controller.
*/
public interface ActivityBlockedCallback {
/** Called when an activity is blocked.*/
void onActivityBlocked(int displayId, ActivityInfo activityInfo);
}
private static final ComponentName BLOCKED_APP_STREAMING_COMPONENT =
new ComponentName("android", BlockedAppStreamingActivity.class.getName());
@@ -89,7 +96,8 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
private final Object mGenericWindowPolicyControllerLock = new Object();
@ActivityPolicy
private final int mDefaultActivityPolicy;
private final Consumer<ActivityInfo> mActivityBlockedCallback;
private final ActivityBlockedCallback mActivityBlockedCallback;
private int mDisplayId = Display.INVALID_DISPLAY;
@NonNull
@GuardedBy("mGenericWindowPolicyControllerLock")
@@ -98,6 +106,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final ArraySet<RunningAppsChangedListener> mRunningAppsChangedListener =
new ArraySet<>();
@Nullable
private final @AssociationRequest.DeviceProfile String mDeviceProfile;
/**
@@ -119,8 +128,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
* {@link VirtualDeviceParams#ACTIVITY_POLICY_DEFAULT_ALLOWED}
* @param defaultActivityPolicy Whether activities are default allowed to be displayed or
* blocked.
* @param activityListener Activity listener to listen for activity changes. The display ID
* is not populated in this callback and is always {@link Display#INVALID_DISPLAY}.
* @param activityListener Activity listener to listen for activity changes.
* @param activityBlockedCallback Callback that is called when an activity is blocked from
* launching.
* @param deviceProfile The {@link AssociationRequest.DeviceProfile} of this virtual device.
@@ -133,7 +141,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
@NonNull Set<ComponentName> blockedActivities,
@ActivityPolicy int defaultActivityPolicy,
@NonNull ActivityListener activityListener,
@NonNull Consumer<ActivityInfo> activityBlockedCallback,
@NonNull ActivityBlockedCallback activityBlockedCallback,
@AssociationRequest.DeviceProfile String deviceProfile) {
super();
mAllowedUsers = allowedUsers;
@@ -148,6 +156,13 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
mDeviceProfile = deviceProfile;
}
/**
* Expected to be called once this object is associated with a newly created display.
*/
public void setDisplayId(int displayId) {
mDisplayId = displayId;
}
/** Register a listener for running applications changes. */
public void registerRunningAppsChangedListener(@NonNull RunningAppsChangedListener listener) {
mRunningAppsChangedListener.add(listener);
@@ -169,7 +184,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
for (int i = 0; i < activityCount; i++) {
final ActivityInfo aInfo = activities.get(i);
if (!canContainActivity(aInfo, /* windowFlags= */ 0, /* systemWindowFlags= */ 0)) {
mActivityBlockedCallback.accept(aInfo);
mActivityBlockedCallback.onActivityBlocked(mDisplayId, aInfo);
return false;
}
}
@@ -191,7 +206,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
}
if (!canContainActivity(activityInfo, /* windowFlags= */ 0, /* systemWindowFlags= */ 0)) {
mActivityBlockedCallback.accept(activityInfo);
mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
return false;
}
@@ -201,14 +216,14 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
if (isNewTask && !mBlockedCrossTaskNavigations.isEmpty()
&& mBlockedCrossTaskNavigations.contains(activityComponent)) {
Slog.d(TAG, "Virtual device blocking cross task navigation of " + activityComponent);
mActivityBlockedCallback.accept(activityInfo);
mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
return false;
}
if (isNewTask && !mAllowedCrossTaskNavigations.isEmpty()
&& !mAllowedCrossTaskNavigations.contains(activityComponent)) {
Slog.d(TAG, "Virtual device not allowing cross task navigation of "
+ activityComponent);
mActivityBlockedCallback.accept(activityInfo);
mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
return false;
}
@@ -220,7 +235,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
public boolean keepActivityOnWindowFlagsChanged(ActivityInfo activityInfo, int windowFlags,
int systemWindowFlags) {
if (!canContainActivity(activityInfo, windowFlags, systemWindowFlags)) {
mActivityBlockedCallback.accept(activityInfo);
mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
return false;
}
return true;
@@ -234,7 +249,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
if (mActivityListener != null && topActivity != null) {
// Post callback on the main thread so it doesn't block activity launching
mHandler.post(() ->
mActivityListener.onTopActivityChanged(Display.INVALID_DISPLAY, topActivity));
mActivityListener.onTopActivityChanged(mDisplayId, topActivity));
}
}
@@ -245,7 +260,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
mRunningUids.addAll(runningUids);
if (mActivityListener != null && mRunningUids.isEmpty()) {
// Post callback on the main thread so it doesn't block activity launching
mHandler.post(() -> mActivityListener.onDisplayEmpty(Display.INVALID_DISPLAY));
mHandler.post(() -> mActivityListener.onDisplayEmpty(mDisplayId));
}
}
mHandler.post(() -> {
@@ -257,7 +272,10 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
@Override
public boolean canShowTasksInRecents() {
// TODO(b/234075973) : Remove this once proper API is ready.
if (mDeviceProfile == null) {
return true;
}
// TODO(b/234075973) : Remove this once proper API is ready.
switch (mDeviceProfile) {
case DEVICE_PROFILE_AUTOMOTIVE_PROJECTION:
return false;

View File

@@ -64,7 +64,6 @@ import android.util.SparseArray;
import android.view.Display;
import android.view.WindowManager;
import android.widget.Toast;
import android.window.DisplayWindowPolicyController;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -110,11 +109,11 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
@GuardedBy("mVirtualDeviceLock")
private boolean mDefaultShowPointerIcon = true;
private ActivityListener createListenerAdapter(int displayId) {
private ActivityListener createListenerAdapter() {
return new ActivityListener() {
@Override
public void onTopActivityChanged(int unusedDisplayId, ComponentName topActivity) {
public void onTopActivityChanged(int displayId, ComponentName topActivity) {
try {
mActivityListener.onTopActivityChanged(displayId, topActivity);
} catch (RemoteException e) {
@@ -123,7 +122,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
}
@Override
public void onDisplayEmpty(int unusedDisplayId) {
public void onDisplayEmpty(int displayId) {
try {
mActivityListener.onDisplayEmpty(displayId);
} catch (RemoteException e) {
@@ -529,24 +528,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
mInputController.dump(fout);
}
DisplayWindowPolicyController onVirtualDisplayCreatedLocked(int displayId) {
GenericWindowPolicyController createWindowPolicyController() {
synchronized (mVirtualDeviceLock) {
if (mVirtualDisplayIds.contains(displayId)) {
throw new IllegalStateException(
"Virtual device already have a virtual display with ID " + displayId);
}
mVirtualDisplayIds.add(displayId);
mInputController.setShowPointerIcon(mDefaultShowPointerIcon, displayId);
mInputController.setPointerAcceleration(1f, displayId);
mInputController.setDisplayEligibilityForPointerCapture(/* isEligible= */ false,
displayId);
mInputController.setLocalIme(displayId);
// Since we're being called in the middle of the display being created, we post a
// task to grab the wakelock instead of doing it synchronously here, to avoid
// reentrancy problems.
mContext.getMainThreadHandler().post(() -> addWakeLockForDisplay(displayId));
final GenericWindowPolicyController gwpc =
new GenericWindowPolicyController(FLAG_SECURE,
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
@@ -556,19 +539,36 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
mParams.getAllowedActivities(),
mParams.getBlockedActivities(),
mParams.getDefaultActivityPolicy(),
createListenerAdapter(displayId),
activityInfo -> onActivityBlocked(displayId, activityInfo),
createListenerAdapter(),
this::onActivityBlocked,
mAssociationInfo.getDeviceProfile());
gwpc.registerRunningAppsChangedListener(/* listener= */ this);
mWindowPolicyControllers.put(displayId, gwpc);
return gwpc;
}
}
void addWakeLockForDisplay(int displayId) {
void onVirtualDisplayCreatedLocked(GenericWindowPolicyController gwpc, int displayId) {
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplayIds.contains(displayId)
|| mPerDisplayWakelocks.containsKey(displayId)) {
if (displayId == Display.INVALID_DISPLAY) {
return;
}
if (mVirtualDisplayIds.contains(displayId)) {
throw new IllegalStateException(
"Virtual device already has a virtual display with ID " + displayId);
}
mVirtualDisplayIds.add(displayId);
gwpc.setDisplayId(displayId);
mWindowPolicyControllers.put(displayId, gwpc);
mInputController.setShowPointerIcon(mDefaultShowPointerIcon, displayId);
mInputController.setPointerAcceleration(1f, displayId);
mInputController.setDisplayEligibilityForPointerCapture(/* isEligible= */ false,
displayId);
mInputController.setLocalIme(displayId);
if (mPerDisplayWakelocks.containsKey(displayId)) {
Slog.e(TAG, "Not creating wakelock for displayId " + displayId);
return;
}
@@ -576,8 +576,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
TAG + ":" + displayId, displayId);
wakeLock.acquire();
mPerDisplayWakelocks.put(displayId, wakeLock);
wakeLock.acquire();
}
}

View File

@@ -31,6 +31,10 @@ import android.companion.virtual.IVirtualDeviceManager;
import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceParams;
import android.content.Context;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplayConfig;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -41,9 +45,9 @@ import android.util.ExceptionUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.widget.Toast;
import android.window.DisplayWindowPolicyController;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.server.SystemService;
import com.android.server.companion.virtual.VirtualDeviceImpl.PendingTrampoline;
@@ -203,6 +207,7 @@ public class VirtualDeviceManagerService extends SystemService {
}
}
@VisibleForTesting
class VirtualDeviceManagerImpl extends IVirtualDeviceManager.Stub implements
VirtualDeviceImpl.PendingTrampolineCallback {
@@ -265,6 +270,50 @@ public class VirtualDeviceManagerService extends SystemService {
}
}
@Override // Binder call
public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
IVirtualDisplayCallback callback, IVirtualDevice virtualDevice, String packageName)
throws RemoteException {
final int callingUid = getCallingUid();
if (!PermissionUtils.validateCallingPackageName(getContext(), packageName)) {
throw new SecurityException(
"Package name " + packageName + " does not belong to calling uid "
+ callingUid);
}
VirtualDeviceImpl virtualDeviceImpl;
synchronized (mVirtualDeviceManagerLock) {
virtualDeviceImpl = mVirtualDevices.get(virtualDevice.getAssociationId());
if (virtualDeviceImpl == null) {
throw new SecurityException("Invalid VirtualDevice");
}
}
if (virtualDeviceImpl.getOwnerUid() != callingUid) {
throw new SecurityException(
"uid " + callingUid
+ " is not the owner of the supplied VirtualDevice");
}
GenericWindowPolicyController gwpc;
final long token = Binder.clearCallingIdentity();
try {
gwpc = virtualDeviceImpl.createWindowPolicyController();
} finally {
Binder.restoreCallingIdentity(token);
}
DisplayManagerInternal displayManager = getLocalService(
DisplayManagerInternal.class);
int displayId = displayManager.createVirtualDisplay(virtualDisplayConfig, callback,
virtualDevice, gwpc, packageName);
final long tokenTwo = Binder.clearCallingIdentity();
try {
virtualDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, displayId);
return displayId;
} finally {
Binder.restoreCallingIdentity(tokenTwo);
}
}
@Nullable
private AssociationInfo getAssociationInfo(String packageName, int associationId) {
final int callingUserId = getCallingUserHandle().getIdentifier();
@@ -336,14 +385,6 @@ public class VirtualDeviceManagerService extends SystemService {
}
}
@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) {

View File

@@ -17,7 +17,6 @@
package com.android.server.companion.virtual;
import android.companion.virtual.IVirtualDevice;
import android.window.DisplayWindowPolicyController;
/**
* Virtual device manager local service interface.
@@ -30,17 +29,6 @@ public abstract class VirtualDeviceManagerInternal {
*/
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.
*

View File

@@ -1231,7 +1231,7 @@ public final class DisplayManagerService extends SystemService {
private int createVirtualDisplayInternal(VirtualDisplayConfig virtualDisplayConfig,
IVirtualDisplayCallback callback, IMediaProjection projection,
IVirtualDevice virtualDevice, String packageName) {
IVirtualDevice virtualDevice, DisplayWindowPolicyController dwpc, String packageName) {
final int callingUid = Binder.getCallingUid();
if (!validatePackageName(callingUid, packageName)) {
throw new SecurityException("packageName must match the calling uid");
@@ -1351,8 +1351,13 @@ public final class DisplayManagerService extends SystemService {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
return createVirtualDisplayLocked(callback, projection, virtualDevice, callingUid,
final int displayId = createVirtualDisplayLocked(callback, projection, callingUid,
packageName, surface, flags, virtualDisplayConfig);
if (displayId != Display.INVALID_DISPLAY && virtualDevice != null && dwpc != null) {
mDisplayWindowPolicyControllers.put(displayId,
Pair.create(virtualDevice, dwpc));
}
return displayId;
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -1360,8 +1365,7 @@ public final class DisplayManagerService extends SystemService {
}
private int createVirtualDisplayLocked(IVirtualDisplayCallback callback,
IMediaProjection projection, IVirtualDevice virtualDevice,
int callingUid, String packageName, Surface surface,
IMediaProjection projection, int callingUid, String packageName, Surface surface,
int flags, VirtualDisplayConfig virtualDisplayConfig) {
if (mVirtualDisplayAdapter == null) {
Slog.w(TAG, "Rejecting request to create private virtual display "
@@ -1389,16 +1393,7 @@ public final class DisplayManagerService extends SystemService {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
if (display != null) {
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 displayId;
return display.getDisplayIdLocked();
}
// Something weird happened and the logical display was not created.
@@ -3066,9 +3061,9 @@ public final class DisplayManagerService extends SystemService {
@Override // Binder call
public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
IVirtualDisplayCallback callback, IMediaProjection projection,
IVirtualDevice virtualDeviceToken, String packageName) {
String packageName) {
return createVirtualDisplayInternal(virtualDisplayConfig, callback, projection,
virtualDeviceToken, packageName);
null, null, packageName);
}
@Override // Binder call
@@ -3534,7 +3529,8 @@ public final class DisplayManagerService extends SystemService {
return !Float.isNaN(refreshRate) && (refreshRate > 0.0f);
}
private final class LocalService extends DisplayManagerInternal {
@VisibleForTesting
final class LocalService extends DisplayManagerInternal {
@Override
public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
@@ -3549,6 +3545,14 @@ public final class DisplayManagerService extends SystemService {
mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATIONS);
}
@Override
public int createVirtualDisplay(VirtualDisplayConfig config,
IVirtualDisplayCallback callback, IVirtualDevice virtualDevice,
DisplayWindowPolicyController dwpc, String packageName) {
return createVirtualDisplayInternal(config, callback, null, virtualDevice, dwpc,
packageName);
}
@Override
public boolean requestPowerState(int groupId, DisplayPowerRequest request,
boolean waitForNegativeProximity) {

View File

@@ -228,36 +228,36 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void onVirtualDisplayRemovedLocked_doesNotThrowException() {
final int displayId = 2;
mDeviceImpl.onVirtualDisplayCreatedLocked(displayId);
mDeviceImpl.onVirtualDisplayCreatedLocked(
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
// This call should not throw any exceptions.
mDeviceImpl.onVirtualDisplayRemovedLocked(displayId);
mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID);
}
@Test
public void onVirtualDisplayCreatedLocked_wakeLockIsAcquired() throws RemoteException {
final int displayId = 2;
mDeviceImpl.onVirtualDisplayCreatedLocked(displayId);
verify(mIPowerManagerMock, never()).acquireWakeLock(any(Binder.class), anyInt(),
nullable(String.class), nullable(String.class), nullable(WorkSource.class),
nullable(String.class), anyInt(), eq(null));
TestableLooper.get(this).processAllMessages();
mDeviceImpl.onVirtualDisplayCreatedLocked(
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(any(Binder.class), anyInt(),
nullable(String.class), nullable(String.class), nullable(WorkSource.class),
nullable(String.class), eq(displayId), eq(null));
nullable(String.class), eq(DISPLAY_ID), eq(null));
}
@Test
public void onVirtualDisplayCreatedLocked_duplicateCalls_onlyOneWakeLockIsAcquired()
throws RemoteException {
final int displayId = 2;
mDeviceImpl.onVirtualDisplayCreatedLocked(displayId);
GenericWindowPolicyController gwpc = mDeviceImpl.createWindowPolicyController();
mDeviceImpl.onVirtualDisplayCreatedLocked(
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
assertThrows(IllegalStateException.class,
() -> mDeviceImpl.onVirtualDisplayCreatedLocked(displayId));
() -> mDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, DISPLAY_ID));
TestableLooper.get(this).processAllMessages();
verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(any(Binder.class), anyInt(),
nullable(String.class), nullable(String.class), nullable(WorkSource.class),
nullable(String.class), eq(displayId), eq(null));
nullable(String.class), eq(DISPLAY_ID), eq(null));
}
@Test
@@ -269,30 +269,30 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void onVirtualDisplayRemovedLocked_wakeLockIsReleased() throws RemoteException {
final int displayId = 2;
mDeviceImpl.onVirtualDisplayCreatedLocked(displayId);
mDeviceImpl.onVirtualDisplayCreatedLocked(
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
TestableLooper.get(this).processAllMessages();
verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(wakeLockCaptor.capture(),
anyInt(),
nullable(String.class), nullable(String.class), nullable(WorkSource.class),
nullable(String.class), eq(displayId), eq(null));
nullable(String.class), eq(DISPLAY_ID), eq(null));
IBinder wakeLock = wakeLockCaptor.getValue();
mDeviceImpl.onVirtualDisplayRemovedLocked(displayId);
mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID);
verify(mIPowerManagerMock, Mockito.times(1)).releaseWakeLock(eq(wakeLock), anyInt());
}
@Test
public void addVirtualDisplay_displayNotReleased_wakeLockIsReleased() throws RemoteException {
final int displayId = 2;
mDeviceImpl.onVirtualDisplayCreatedLocked(displayId);
mDeviceImpl.onVirtualDisplayCreatedLocked(
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
TestableLooper.get(this).processAllMessages();
verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(wakeLockCaptor.capture(),
anyInt(),
nullable(String.class), nullable(String.class), nullable(WorkSource.class),
nullable(String.class), eq(displayId), eq(null));
nullable(String.class), eq(DISPLAY_ID), eq(null));
IBinder wakeLock = wakeLockCaptor.getValue();
// Close the VirtualDevice without first notifying it of the VirtualDisplay removal.
@@ -416,7 +416,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void onAudioSessionStarting_hasVirtualAudioController() {
mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
mDeviceImpl.onVirtualDisplayCreatedLocked(
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mRoutingCallback, mConfigChangedCallback);
@@ -425,7 +426,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void onAudioSessionEnded_noVirtualAudioController() {
mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
mDeviceImpl.onVirtualDisplayCreatedLocked(
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mRoutingCallback, mConfigChangedCallback);
mDeviceImpl.onAudioSessionEnded();
@@ -435,7 +437,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void close_cleanVirtualAudioController() {
mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
mDeviceImpl.onVirtualDisplayCreatedLocked(
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mRoutingCallback, mConfigChangedCallback);
mDeviceImpl.close();
@@ -659,7 +662,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void openNonBlockedAppOnVirtualDisplay_doesNotStartBlockedAlertActivity() {
mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
mDeviceImpl.onVirtualDisplayCreatedLocked(
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID);
doNothing().when(mContext).startActivityAsUser(any(), any(), any());
@@ -677,7 +681,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void openPermissionControllerOnVirtualDisplay_startBlockedAlertActivity() {
mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
mDeviceImpl.onVirtualDisplayCreatedLocked(
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID);
doNothing().when(mContext).startActivityAsUser(any(), any(), any());
@@ -695,7 +700,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void openSettingsOnVirtualDisplay_startBlockedAlertActivity() {
mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
mDeviceImpl.onVirtualDisplayCreatedLocked(
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID);
doNothing().when(mContext).startActivityAsUser(any(), any(), any());
@@ -713,7 +719,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void openVendingOnVirtualDisplay_startBlockedAlertActivity() {
mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
mDeviceImpl.onVirtualDisplayCreatedLocked(
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID);
doNothing().when(mContext).startActivityAsUser(any(), any(), any());
@@ -731,7 +738,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void openGoogleDialerOnVirtualDisplay_startBlockedAlertActivity() {
mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
mDeviceImpl.onVirtualDisplayCreatedLocked(
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID);
doNothing().when(mContext).startActivityAsUser(any(), any(), any());
@@ -749,7 +757,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void openGoogleMapsOnVirtualDisplay_startBlockedAlertActivity() {
mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
mDeviceImpl.onVirtualDisplayCreatedLocked(
mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID);
doNothing().when(mContext).startActivityAsUser(any(), any(), any());

View File

@@ -45,6 +45,7 @@ import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.Curve;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayViewport;
import android.hardware.display.DisplayedContentSample;
import android.hardware.display.DisplayedContentSamplingAttributes;
@@ -63,6 +64,7 @@ import android.view.DisplayEventReceiver;
import android.view.DisplayInfo;
import android.view.Surface;
import android.view.SurfaceControl;
import android.window.DisplayWindowPolicyController;
import androidx.test.InstrumentationRegistry;
import androidx.test.core.app.ApplicationProvider;
@@ -220,7 +222,7 @@ public class DisplayManagerServiceTest {
builder.setUniqueId(uniqueId);
builder.setFlags(flags);
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
null /* projection */, null /* virtualDeviceToken */, PACKAGE_NAME);
null /* projection */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -346,7 +348,7 @@ public class DisplayManagerServiceTest {
builder.setFlags(flags);
builder.setUniqueId(uniqueId);
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
null /* projection */, null /* virtualDeviceToken */, PACKAGE_NAME);
null /* projection */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -586,8 +588,7 @@ public class DisplayManagerServiceTest {
VIRTUAL_DISPLAY_NAME, width, height, dpi);
builder.setUniqueId(uniqueId);
final int firstDisplayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, null /* projection */, null /* virtualDeviceToken */,
PACKAGE_NAME);
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
// The second virtual display requests to mirror the first virtual display.
final String uniqueId2 = "uniqueId --- displayIdToMirrorTest #2";
@@ -598,7 +599,7 @@ public class DisplayManagerServiceTest {
builder2.setDisplayIdToMirror(firstDisplayId);
final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(),
mMockAppToken2 /* callback */, null /* projection */,
null /* virtualDeviceToken */, PACKAGE_NAME);
PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler
@@ -636,8 +637,7 @@ public class DisplayManagerServiceTest {
builder.setSurface(surface);
builder.setUniqueId(uniqueId);
final int displayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, null /* projection */, null /* virtualDeviceToken */,
PACKAGE_NAME);
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -669,7 +669,7 @@ public class DisplayManagerServiceTest {
builder.setUniqueId("uniqueId --- OWN_DISPLAY_GROUP");
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
null /* projection */, null /* virtualDeviceToken */, PACKAGE_NAME);
null /* projection */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
@@ -700,7 +700,7 @@ public class DisplayManagerServiceTest {
try {
bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
null /* projection */, null /* virtualDeviceToken */, PACKAGE_NAME);
null /* projection */, PACKAGE_NAME);
fail("Creating virtual display with VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP without "
+ "ADD_TRUSTED_DISPLAY permission should throw SecurityException.");
} catch (SecurityException e) {
@@ -716,6 +716,8 @@ public class DisplayManagerServiceTest {
public void testOwnDisplayGroup_allowCreationWithVirtualDevice() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerInternal localService = displayManager.new LocalService();
registerDefaultDisplays(displayManager);
DisplayManagerService.BinderService bs = displayManager.new BinderService();
@@ -733,8 +735,9 @@ public class DisplayManagerServiceTest {
when(mMockVirtualDeviceManagerInternal.isValidVirtualDevice(virtualDevice))
.thenReturn(true);
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
null /* projection */, virtualDevice /* virtualDeviceToken */, PACKAGE_NAME);
int displayId = localService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class), PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);