Merge "Small changes in VDMS w.r.t. caching and camera controller."

This commit is contained in:
TreeHugger Robot
2023-01-05 14:11:47 +00:00
committed by Android (Google) Code Review
5 changed files with 140 additions and 141 deletions

View File

@@ -19,6 +19,7 @@ package com.android.server.companion.virtual;
import static android.hardware.camera2.CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_UNSUPPORTED;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -94,6 +95,23 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
mUserManager = mContext.getSystemService(UserManager.class);
}
/**
* Returns the userId for which the camera access should be blocked.
*/
@UserIdInt
public int getUserId() {
return mContext.getUserId();
}
/**
* Returns the number of observers currently relying on this controller.
*/
public int getObserverCount() {
synchronized (mLock) {
return mObserverCount;
}
}
/**
* Starts watching for camera access by uids running on a virtual device, if we were not
* already doing so.

View File

@@ -110,6 +110,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
private final int mDeviceId;
private final InputController mInputController;
private final SensorController mSensorController;
private final CameraAccessController mCameraAccessController;
private VirtualAudioController mVirtualAudioController;
@VisibleForTesting
final Set<Integer> mVirtualDisplayIds = new ArraySet<>();
@@ -165,6 +166,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
IBinder token,
int ownerUid,
int deviceId,
CameraAccessController cameraAccessController,
OnDeviceCloseListener onDeviceCloseListener,
PendingTrampolineCallback pendingTrampolineCallback,
IVirtualDeviceActivityListener activityListener,
@@ -178,6 +180,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
deviceId,
/* inputController= */ null,
/* sensorController= */ null,
cameraAccessController,
onDeviceCloseListener,
pendingTrampolineCallback,
activityListener,
@@ -194,6 +197,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
int deviceId,
InputController inputController,
SensorController sensorController,
CameraAccessController cameraAccessController,
OnDeviceCloseListener onDeviceCloseListener,
PendingTrampolineCallback pendingTrampolineCallback,
IVirtualDeviceActivityListener activityListener,
@@ -223,6 +227,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
} else {
mSensorController = sensorController;
}
mCameraAccessController = cameraAccessController;
mCameraAccessController.startObservingIfNeeded();
mOnDeviceCloseListener = onDeviceCloseListener;
try {
token.linkToDeath(this, 0);
@@ -243,6 +249,11 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
return flags;
}
/** Returns the camera access controller of this device. */
CameraAccessController getCameraAccessController() {
return mCameraAccessController;
}
/** Returns the device display name. */
CharSequence getDisplayName() {
return mAssociationInfo.getDisplayName();
@@ -359,6 +370,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
}
mOnDeviceCloseListener.onClose(mDeviceId);
mAppToken.unlinkToDeath(this, 0);
mCameraAccessController.stopObservingIfNeeded();
final long ident = Binder.clearCallingIdentity();
try {
@@ -376,6 +388,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
@Override
public void onRunningAppsChanged(ArraySet<Integer> runningUids) {
mCameraAccessController.blockCameraAccessIfNeeded(runningUids);
mRunningAppsChangedCallback.accept(runningUids);
}

View File

@@ -27,7 +27,6 @@ import android.annotation.SuppressLint;
import android.app.ActivityOptions;
import android.companion.AssociationInfo;
import android.companion.CompanionDeviceManager;
import android.companion.CompanionDeviceManager.OnAssociationsChangedListener;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDeviceActivityListener;
import android.companion.virtual.IVirtualDeviceManager;
@@ -70,6 +69,7 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
@SuppressLint("LongLogTag")
@@ -86,20 +86,6 @@ public class VirtualDeviceManagerService extends SystemService {
private static AtomicInteger sNextUniqueIndex = new AtomicInteger(
VirtualDeviceManager.DEVICE_ID_DEFAULT + 1);
/**
* Mapping from user IDs to CameraAccessControllers.
*/
@GuardedBy("mVirtualDeviceManagerLock")
private final SparseArray<CameraAccessController> mCameraAccessControllers =
new SparseArray<>();
/**
* Mapping from device IDs to CameraAccessControllers.
*/
@GuardedBy("mVirtualDeviceManagerLock")
private final SparseArray<CameraAccessController> mCameraAccessControllersByDeviceId =
new SparseArray<>();
/**
* Mapping from device IDs to virtual devices.
*/
@@ -112,21 +98,6 @@ public class VirtualDeviceManagerService extends SystemService {
@GuardedBy("mVirtualDeviceManagerLock")
private final SparseArray<ArraySet<Integer>> mAppsOnVirtualDevices = new SparseArray<>();
/**
* Mapping from user ID to CDM associations. The associations come from
* {@link CompanionDeviceManager#getAllAssociations()}, which contains associations across all
* packages.
*/
private final ConcurrentHashMap<Integer, List<AssociationInfo>> mAllAssociations =
new ConcurrentHashMap<>();
/**
* Mapping from user ID to its change listener. The listeners are added when the user is
* started and removed when the user stops.
*/
private final SparseArray<OnAssociationsChangedListener> mOnAssociationsChangedListeners =
new SparseArray<>();
public VirtualDeviceManagerService(Context context) {
super(context);
mImpl = new VirtualDeviceManagerImpl();
@@ -177,54 +148,9 @@ public class VirtualDeviceManagerService extends SystemService {
}
}
@Override
public void onUserStarting(@NonNull TargetUser user) {
super.onUserStarting(user);
Context userContext = getContext().createContextAsUser(user.getUserHandle(), 0);
synchronized (mVirtualDeviceManagerLock) {
final CompanionDeviceManager cdm =
userContext.getSystemService(CompanionDeviceManager.class);
final int userId = user.getUserIdentifier();
mAllAssociations.put(userId, cdm.getAllAssociations());
OnAssociationsChangedListener listener =
associations -> mAllAssociations.put(userId, associations);
mOnAssociationsChangedListeners.put(userId, listener);
cdm.addOnAssociationsChangedListener(Runnable::run, listener);
CameraAccessController cameraAccessController = new CameraAccessController(
userContext, mLocalService, this::onCameraAccessBlocked);
mCameraAccessControllers.put(user.getUserIdentifier(), cameraAccessController);
}
}
@Override
public void onUserStopping(@NonNull TargetUser user) {
super.onUserStopping(user);
synchronized (mVirtualDeviceManagerLock) {
int userId = user.getUserIdentifier();
mAllAssociations.remove(userId);
final CompanionDeviceManager cdm = getContext().createContextAsUser(
user.getUserHandle(), 0)
.getSystemService(CompanionDeviceManager.class);
OnAssociationsChangedListener listener = mOnAssociationsChangedListeners.get(userId);
if (listener != null) {
cdm.removeOnAssociationsChangedListener(listener);
mOnAssociationsChangedListeners.remove(userId);
}
CameraAccessController cameraAccessController = mCameraAccessControllers.get(
user.getUserIdentifier());
if (cameraAccessController != null) {
cameraAccessController.close();
mCameraAccessControllers.remove(user.getUserIdentifier());
} else {
Slog.w(TAG, "Cannot unregister cameraAccessController for user " + user);
}
}
}
void onCameraAccessBlocked(int appUid) {
synchronized (mVirtualDeviceManagerLock) {
int size = mVirtualDevices.size();
for (int i = 0; i < size; i++) {
for (int i = 0; i < mVirtualDevices.size(); i++) {
CharSequence deviceName = mVirtualDevices.valueAt(i).getDisplayName();
mVirtualDevices.valueAt(i).showToastWhereUidIsRunning(appUid,
getContext().getString(
@@ -235,6 +161,21 @@ public class VirtualDeviceManagerService extends SystemService {
}
}
CameraAccessController getCameraAccessController(UserHandle userHandle) {
int userId = userHandle.getIdentifier();
synchronized (mVirtualDeviceManagerLock) {
for (int i = 0; i < mVirtualDevices.size(); i++) {
final CameraAccessController cameraAccessController =
mVirtualDevices.valueAt(i).getCameraAccessController();
if (cameraAccessController.getUserId() == userId) {
return cameraAccessController;
}
}
}
Context userContext = getContext().createContextAsUser(userHandle, 0);
return new CameraAccessController(userContext, mLocalService, this::onCameraAccessBlocked);
}
@VisibleForTesting
VirtualDeviceManagerInternal getLocalServiceInstance() {
return mLocalService;
@@ -255,8 +196,34 @@ public class VirtualDeviceManagerService extends SystemService {
}
}
class VirtualDeviceManagerImpl extends IVirtualDeviceManager.Stub implements
VirtualDeviceImpl.PendingTrampolineCallback {
@VisibleForTesting
void removeVirtualDevice(int deviceId) {
synchronized (mVirtualDeviceManagerLock) {
mAppsOnVirtualDevices.remove(deviceId);
mVirtualDevices.remove(deviceId);
}
}
class VirtualDeviceManagerImpl extends IVirtualDeviceManager.Stub {
private final VirtualDeviceImpl.PendingTrampolineCallback mPendingTrampolineCallback =
new VirtualDeviceImpl.PendingTrampolineCallback() {
@Override
public void startWaitingForPendingTrampoline(PendingTrampoline pendingTrampoline) {
PendingTrampoline existing = mPendingTrampolines.put(
pendingTrampoline.mPendingIntent.getCreatorPackage(),
pendingTrampoline);
if (existing != null) {
existing.mResultReceiver.send(
VirtualDeviceManager.LAUNCH_FAILURE_NO_ACTIVITY, null);
}
}
@Override
public void stopWaitingForPendingTrampoline(PendingTrampoline pendingTrampoline) {
mPendingTrampolines.remove(pendingTrampoline.mPendingIntent.getCreatorPackage());
}
};
@Override // Binder call
public IVirtualDevice createVirtualDevice(
@@ -279,25 +246,16 @@ public class VirtualDeviceManagerService extends SystemService {
throw new IllegalArgumentException("No association with ID " + associationId);
}
synchronized (mVirtualDeviceManagerLock) {
final int userId = UserHandle.getUserId(callingUid);
final UserHandle userHandle = getCallingUserHandle();
final CameraAccessController cameraAccessController =
mCameraAccessControllers.get(userId);
getCameraAccessController(userHandle);
final int deviceId = sNextUniqueIndex.getAndIncrement();
final Consumer<ArraySet<Integer>> runningAppsChangedCallback =
runningUids -> notifyRunningAppsChanged(deviceId, runningUids);
VirtualDeviceImpl virtualDevice = new VirtualDeviceImpl(getContext(),
associationInfo, token, callingUid, deviceId,
/* onDeviceCloseListener= */ this::onDeviceClosed,
this, activityListener,
runningUids -> {
cameraAccessController.blockCameraAccessIfNeeded(runningUids);
notifyRunningAppsChanged(deviceId, runningUids);
},
params);
if (cameraAccessController != null) {
cameraAccessController.startObservingIfNeeded();
mCameraAccessControllersByDeviceId.put(deviceId, cameraAccessController);
} else {
Slog.w(TAG, "cameraAccessController not found for user " + userId);
}
associationInfo, token, callingUid, deviceId, cameraAccessController,
this::onDeviceClosed, mPendingTrampolineCallback, activityListener,
runningAppsChangedCallback, params);
mVirtualDevices.put(deviceId, virtualDevice);
return virtualDevice;
}
@@ -409,8 +367,18 @@ public class VirtualDeviceManagerService extends SystemService {
@Nullable
private AssociationInfo getAssociationInfo(String packageName, int associationId) {
final int callingUserId = getCallingUserHandle().getIdentifier();
final List<AssociationInfo> associations = mAllAssociations.get(callingUserId);
final UserHandle userHandle = getCallingUserHandle();
final CompanionDeviceManager cdm =
getContext().createContextAsUser(userHandle, 0)
.getSystemService(CompanionDeviceManager.class);
List<AssociationInfo> associations;
final long identity = Binder.clearCallingIdentity();
try {
associations = cdm.getAllAssociations();
} finally {
Binder.restoreCallingIdentity(identity);
}
final int callingUserId = userHandle.getIdentifier();
if (associations != null) {
final int associationSize = associations.size();
for (int i = 0; i < associationSize; i++) {
@@ -427,25 +395,15 @@ public class VirtualDeviceManagerService extends SystemService {
}
private void onDeviceClosed(int deviceId) {
synchronized (mVirtualDeviceManagerLock) {
mVirtualDevices.remove(deviceId);
Intent i = new Intent(VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED);
i.putExtra(VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID, deviceId);
i.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
final long identity = Binder.clearCallingIdentity();
try {
getContext().sendBroadcastAsUser(i, UserHandle.ALL);
} finally {
Binder.restoreCallingIdentity(identity);
}
mAppsOnVirtualDevices.remove(deviceId);
final CameraAccessController cameraAccessController =
mCameraAccessControllersByDeviceId.removeReturnOld(deviceId);
if (cameraAccessController != null) {
cameraAccessController.stopObservingIfNeeded();
} else {
Slog.w(TAG, "cameraAccessController not found for device Id " + deviceId);
}
removeVirtualDevice(deviceId);
Intent i = new Intent(VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED);
i.putExtra(VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID, deviceId);
i.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
final long identity = Binder.clearCallingIdentity();
try {
getContext().sendBroadcastAsUser(i, UserHandle.ALL);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@@ -474,22 +432,6 @@ public class VirtualDeviceManagerService extends SystemService {
}
}
}
@Override
public void startWaitingForPendingTrampoline(PendingTrampoline pendingTrampoline) {
PendingTrampoline existing = mPendingTrampolines.put(
pendingTrampoline.mPendingIntent.getCreatorPackage(),
pendingTrampoline);
if (existing != null) {
existing.mResultReceiver.send(
VirtualDeviceManager.LAUNCH_FAILURE_NO_ACTIVITY, null);
}
}
@Override
public void stopWaitingForPendingTrampoline(PendingTrampoline pendingTrampoline) {
mPendingTrampolines.remove(pendingTrampoline.mPendingIntent.getCreatorPackage());
}
}
private final class LocalService extends VirtualDeviceManagerInternal {

View File

@@ -18,6 +18,8 @@ package com.android.server.companion.virtual;
import static android.hardware.camera2.CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_UNSUPPORTED;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
@@ -115,6 +117,11 @@ public class CameraAccessControllerTest {
mController.startObservingIfNeeded();
}
@Test
public void getUserId_returnsCorrectId() {
assertThat(mController.getUserId()).isEqualTo(mContext.getUserId());
}
@Test
public void onCameraOpened_uidNotRunning_noCameraBlocking() throws CameraAccessException {
when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(

View File

@@ -203,6 +203,7 @@ public class VirtualDeviceManagerServiceTest {
private VirtualDeviceImpl mDeviceImpl;
private InputController mInputController;
private SensorController mSensorController;
private CameraAccessController mCameraAccessController;
private AssociationInfo mAssociationInfo;
private VirtualDeviceManagerService mVdms;
private VirtualDeviceManagerInternal mLocalService;
@@ -237,6 +238,8 @@ public class VirtualDeviceManagerServiceTest {
@Mock
private IAudioConfigChangedCallback mConfigChangedCallback;
@Mock
private CameraAccessController.CameraAccessBlockedCallback mCameraAccessBlockedCallback;
@Mock
private ApplicationInfo mApplicationInfoMock;
@Mock
IInputManager mIInputManagerMock;
@@ -325,6 +328,8 @@ public class VirtualDeviceManagerServiceTest {
new Handler(TestableLooper.get(this).getLooper()),
mContext.getSystemService(WindowManager.class), threadVerifier);
mSensorController = new SensorController(new Object(), VIRTUAL_DEVICE_ID_1);
mCameraAccessController =
new CameraAccessController(mContext, mLocalService, mCameraAccessBlockedCallback);
mAssociationInfo = new AssociationInfo(/* associationId= */ 1, 0, null,
MacAddress.BROADCAST_ADDRESS, "", null, null, true, false, false, 0, 0);
@@ -394,12 +399,7 @@ public class VirtualDeviceManagerServiceTest {
.setBlockedActivities(getBlockedActivities())
.setDevicePolicy(POLICY_TYPE_SENSORS, DEVICE_POLICY_CUSTOM)
.build();
mDeviceImpl = new VirtualDeviceImpl(mContext,
mAssociationInfo, new Binder(), /* ownerUid */ 0, VIRTUAL_DEVICE_ID_1,
mInputController, mSensorController,
/* onDeviceCloseListener= */ (int deviceId) -> {},
mPendingTrampolineCallback, mActivityListener, mRunningAppsChangedCallback, params);
mVdms.addVirtualDevice(mDeviceImpl);
mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
assertThat(mVdm.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS))
.isEqualTo(DEVICE_POLICY_CUSTOM);
@@ -557,6 +557,21 @@ public class VirtualDeviceManagerServiceTest {
LocaleList.forLanguageTags(firstKeyboardConfig.getLanguageTag()));
}
@Test
public void cameraAccessController_observerCountUpdated() {
assertThat(mCameraAccessController.getObserverCount()).isEqualTo(1);
VirtualDeviceImpl secondDevice =
createVirtualDevice(VIRTUAL_DEVICE_ID_2, DEVICE_OWNER_UID_2);
assertThat(mCameraAccessController.getObserverCount()).isEqualTo(2);
mDeviceImpl.close();
assertThat(mCameraAccessController.getObserverCount()).isEqualTo(1);
secondDevice.close();
assertThat(mCameraAccessController.getObserverCount()).isEqualTo(0);
}
@Test
public void onVirtualDisplayRemovedLocked_doesNotThrowException() {
mDeviceImpl.onVirtualDisplayCreatedLocked(
@@ -1543,14 +1558,18 @@ public class VirtualDeviceManagerServiceTest {
}
private VirtualDeviceImpl createVirtualDevice(int virtualDeviceId, int ownerUid) {
VirtualDeviceParams params = new VirtualDeviceParams
.Builder()
VirtualDeviceParams params = new VirtualDeviceParams.Builder()
.setBlockedActivities(getBlockedActivities())
.build();
return createVirtualDevice(virtualDeviceId, ownerUid, params);
}
private VirtualDeviceImpl createVirtualDevice(int virtualDeviceId, int ownerUid,
VirtualDeviceParams params) {
VirtualDeviceImpl virtualDeviceImpl = new VirtualDeviceImpl(mContext,
mAssociationInfo, new Binder(), ownerUid, virtualDeviceId,
mInputController, mSensorController,
/* onDeviceCloseListener= */ (int deviceId) -> {},
mInputController, mSensorController, mCameraAccessController,
/* onDeviceCloseListener= */ deviceId -> mVdms.removeVirtualDevice(deviceId),
mPendingTrampolineCallback, mActivityListener, mRunningAppsChangedCallback, params);
mVdms.addVirtualDevice(virtualDeviceImpl);
return virtualDeviceImpl;