Add isValidVirtualDeviceId api to VDM

Remove equivalent method from LocalService and use
this one instead.

Also update ContextImpl to use the API

Bug: 263355088
Test: atest VirtualDeviceManagerServiceTest
Change-Id: Ic2721d5104cbaa2ddaa6b51e8a4734fc0606c1c2
This commit is contained in:
Marco Loaiza
2023-01-03 15:14:33 +00:00
parent 6529d77f37
commit 7de5897932
8 changed files with 88 additions and 70 deletions

View File

@@ -26,9 +26,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiContext;
import android.companion.virtual.VirtualDevice;
import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceParams;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.AttributionSource;
import android.content.AutofillOptions;
@@ -2742,9 +2740,12 @@ class ContextImpl extends Context {
@Override
public @NonNull Context createDeviceContext(int deviceId) {
if (!isValidDeviceId(deviceId)) {
throw new IllegalArgumentException(
"Not a valid ID of the default device or any virtual device: " + deviceId);
if (deviceId != VirtualDeviceManager.DEVICE_ID_DEFAULT) {
VirtualDeviceManager vdm = getSystemService(VirtualDeviceManager.class);
if (!vdm.isValidVirtualDeviceId(deviceId)) {
throw new IllegalArgumentException(
"Not a valid ID of the default device or any virtual device: " + deviceId);
}
}
ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams,
@@ -2757,31 +2758,6 @@ class ContextImpl extends Context {
return context;
}
/**
* Checks whether the passed {@code deviceId} is valid or not.
* {@link VirtualDeviceManager#DEVICE_ID_DEFAULT} is valid as it is the ID of the default
* device when no additional virtual devices exist. If {@code deviceId} is the id of
* a virtual device, it should correspond to a virtual device created by
* {@link VirtualDeviceManager#createVirtualDevice(int, VirtualDeviceParams)}.
*/
private boolean isValidDeviceId(int deviceId) {
if (deviceId == VirtualDeviceManager.DEVICE_ID_DEFAULT) {
return true;
}
if (deviceId > VirtualDeviceManager.DEVICE_ID_DEFAULT) {
VirtualDeviceManager vdm = getSystemService(VirtualDeviceManager.class);
if (vdm != null) {
List<VirtualDevice> virtualDevices = vdm.getVirtualDevices();
for (int i = 0; i < virtualDevices.size(); i++) {
if (virtualDevices.get(i).getDeviceId() == deviceId) {
return true;
}
}
}
}
return false;
}
@NonNull
@Override
public WindowContext createWindowContext(@WindowType int type,
@@ -3044,10 +3020,13 @@ class ContextImpl extends Context {
@Override
public void updateDeviceId(int updatedDeviceId) {
if (!isValidDeviceId(updatedDeviceId)) {
throw new IllegalArgumentException(
"Not a valid ID of the default device or any virtual device: "
+ updatedDeviceId);
if (updatedDeviceId != VirtualDeviceManager.DEVICE_ID_DEFAULT) {
VirtualDeviceManager vdm = getSystemService(VirtualDeviceManager.class);
if (!vdm.isValidVirtualDeviceId(updatedDeviceId)) {
throw new IllegalArgumentException(
"Not a valid ID of the default device or any virtual device: "
+ updatedDeviceId);
}
}
if (mIsExplicitDeviceId) {
throw new UnsupportedOperationException(

View File

@@ -56,6 +56,14 @@ interface IVirtualDeviceManager {
*/
int getDeviceIdForDisplayId(int displayId);
/**
* Checks whether the passed {@code deviceId} is a valid virtual device ID or not.
* {@link VirtualDeviceManager#DEVICE_ID_DEFAULT} is not valid as it is the ID of the default
* device which is not a virtual device. {@code deviceId} must correspond to a virtual device
* created by {@link VirtualDeviceManager#createVirtualDevice(int, VirtualDeviceParams)}.
*/
boolean isValidVirtualDeviceId(int deviceId);
/**
* Returns the device policy for the given virtual device and policy type.
*/

View File

@@ -257,6 +257,26 @@ public final class VirtualDeviceManager {
}
}
/**
* Checks whether the passed {@code deviceId} is a valid virtual device ID or not.
* {@link VirtualDeviceManager#DEVICE_ID_DEFAULT} is not valid as it is the ID of the default
* device which is not a virtual device. {@code deviceId} must correspond to a virtual device
* created by {@link VirtualDeviceManager#createVirtualDevice(int, VirtualDeviceParams)}.
*
* @hide
*/
public boolean isValidVirtualDeviceId(int deviceId) {
if (mService == null) {
Log.w(TAG, "Failed to retrieve virtual devices; no virtual device manager service.");
return false;
}
try {
return mService.isValidVirtualDeviceId(deviceId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Returns device-specific audio session id for audio playback.
*

View File

@@ -139,15 +139,6 @@ public class VirtualDeviceManagerService extends SystemService {
mActivityInterceptorCallback);
}
@GuardedBy("mVirtualDeviceManagerLock")
private boolean isValidVirtualDeviceLocked(IVirtualDevice virtualDevice) {
try {
return mVirtualDevices.contains(virtualDevice.getDeviceId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
void onCameraAccessBlocked(int appUid) {
synchronized (mVirtualDeviceManagerLock) {
for (int i = 0; i < mVirtualDevices.size(); i++) {
@@ -347,6 +338,14 @@ public class VirtualDeviceManagerService extends SystemService {
return VirtualDeviceManager.DEVICE_ID_DEFAULT;
}
// Binder call
@Override
public boolean isValidVirtualDeviceId(int deviceId) {
synchronized (mVirtualDeviceManagerLock) {
return mVirtualDevices.contains(deviceId);
}
}
@Override // Binder call
public int getAudioPlaybackSessionId(int deviceId) {
synchronized (mVirtualDeviceManagerLock) {
@@ -444,13 +443,6 @@ public class VirtualDeviceManagerService extends SystemService {
@GuardedBy("mVirtualDeviceManagerLock")
private final ArraySet<Integer> mAllUidsOnVirtualDevice = new ArraySet<>();
@Override
public boolean isValidVirtualDevice(IVirtualDevice virtualDevice) {
synchronized (mVirtualDeviceManagerLock) {
return isValidVirtualDeviceLocked(virtualDevice);
}
}
@Override
public int getDeviceOwnerUid(int deviceId) {
synchronized (mVirtualDeviceManagerLock) {

View File

@@ -67,11 +67,6 @@ public abstract class VirtualDeviceManagerInternal {
*/
public abstract void onAppsOnVirtualDeviceChanged();
/**
* Validate the virtual device.
*/
public abstract boolean isValidVirtualDevice(IVirtualDevice virtualDevice);
/**
* Gets the owner uid for a deviceId.
*

View File

@@ -47,6 +47,7 @@ import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.compat.CompatChanges;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.VirtualDeviceManager;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.BroadcastReceiver;
@@ -1273,12 +1274,17 @@ public final class DisplayManagerService extends SystemService {
final Surface surface = virtualDisplayConfig.getSurface();
int flags = virtualDisplayConfig.getFlags();
if (virtualDevice != null) {
final VirtualDeviceManagerInternal vdm =
getLocalService(VirtualDeviceManagerInternal.class);
if (!vdm.isValidVirtualDevice(virtualDevice)) {
throw new SecurityException("Invalid virtual device");
final VirtualDeviceManager vdm = mContext.getSystemService(VirtualDeviceManager.class);
try {
if (!vdm.isValidVirtualDeviceId(virtualDevice.getDeviceId())) {
throw new SecurityException("Invalid virtual device");
}
} catch (RemoteException ex) {
throw new SecurityException("Unable to validate virtual device");
}
flags |= vdm.getBaseVirtualDisplayFlags(virtualDevice);
final VirtualDeviceManagerInternal localVdm =
getLocalService(VirtualDeviceManagerInternal.class);
flags |= localVdm.getBaseVirtualDisplayFlags(virtualDevice);
}
if (surface != null && surface.isSingleBuffered()) {

View File

@@ -368,6 +368,21 @@ public class VirtualDeviceManagerServiceTest {
.isEqualTo(mDeviceImpl.getDeviceId());
}
@Test
public void isDeviceIdValid_defaultDeviceId_returnsFalse() {
assertThat(mVdm.isValidVirtualDeviceId(DEVICE_ID_DEFAULT)).isFalse();
}
@Test
public void isDeviceIdValid_validVirtualDeviceId_returnsTrue() {
assertThat(mVdm.isValidVirtualDeviceId(mDeviceImpl.getDeviceId())).isTrue();
}
@Test
public void isDeviceIdValid_nonExistentDeviceId_returnsFalse() {
assertThat(mVdm.isValidVirtualDeviceId(mDeviceImpl.getDeviceId() + 1)).isFalse();
}
@Test
public void getDevicePolicy_invalidDeviceId_returnsDefault() {
assertThat(mVdm.getDevicePolicy(DEVICE_ID_INVALID, POLICY_TYPE_SENSORS))

View File

@@ -39,6 +39,8 @@ import static org.mockito.Mockito.when;
import android.app.PropertyInvalidatedCache;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDeviceManager;
import android.companion.virtual.VirtualDeviceManager;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.Context;
import android.content.ContextWrapper;
@@ -173,6 +175,7 @@ public class DisplayManagerServiceTest {
private final DisplayManagerService.Injector mBasicInjector = new BasicInjector();
@Mock IVirtualDeviceManager mIVirtualDeviceManager;
@Mock InputManagerInternal mMockInputManagerInternal;
@Mock VirtualDeviceManagerInternal mMockVirtualDeviceManagerInternal;
@Mock IVirtualDisplayCallback.Stub mMockAppToken;
@@ -202,6 +205,8 @@ public class DisplayManagerServiceTest {
mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
VirtualDeviceManager vdm = new VirtualDeviceManager(mIVirtualDeviceManager, mContext);
when(mContext.getSystemService(VirtualDeviceManager.class)).thenReturn(vdm);
// Disable binder caches in this process.
PropertyInvalidatedCache.disableForTestMode();
setUpDisplay();
@@ -727,10 +732,8 @@ public class DisplayManagerServiceTest {
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
when(mMockVirtualDeviceManagerInternal.isValidVirtualDevice(virtualDevice))
.thenReturn(true);
when(virtualDevice.getDeviceId()).thenReturn(1);
when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
// Create a first virtual display. A display group should be created for this display on the
// virtual device.
final VirtualDisplayConfig.Builder builder1 =
@@ -780,9 +783,8 @@ public class DisplayManagerServiceTest {
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
when(mMockVirtualDeviceManagerInternal.isValidVirtualDevice(virtualDevice))
.thenReturn(true);
when(virtualDevice.getDeviceId()).thenReturn(1);
when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
// Create a first virtual display. A display group should be created for this display on the
// virtual device.
@@ -806,6 +808,8 @@ public class DisplayManagerServiceTest {
.setFlags(VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP)
.setUniqueId("uniqueId --- own display group");
when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
int displayId2 =
localService.createVirtualDisplay(
builder2.build(),
@@ -832,9 +836,8 @@ public class DisplayManagerServiceTest {
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
when(mMockVirtualDeviceManagerInternal.isValidVirtualDevice(virtualDevice))
.thenReturn(true);
when(virtualDevice.getDeviceId()).thenReturn(1);
when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
// Allow an ALWAYS_UNLOCKED display to be created.
when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY))
@@ -1062,7 +1065,7 @@ public class DisplayManagerServiceTest {
* a virtual device, even if ADD_TRUSTED_DISPLAY is not granted.
*/
@Test
public void testOwnDisplayGroup_allowCreationWithVirtualDevice() {
public void testOwnDisplayGroup_allowCreationWithVirtualDevice() throws Exception {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerInternal localService = displayManager.new LocalService();
@@ -1081,8 +1084,8 @@ public class DisplayManagerServiceTest {
builder.setUniqueId("uniqueId --- OWN_DISPLAY_GROUP");
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
when(mMockVirtualDeviceManagerInternal.isValidVirtualDevice(virtualDevice))
.thenReturn(true);
when(virtualDevice.getDeviceId()).thenReturn(1);
when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
int displayId = localService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */,