summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Cliff Wu <cliffwu@google.com> 2022-09-11 18:20:27 +0800
committer Cliff Wu <cliffwu@google.com> 2022-09-22 14:20:23 +0000
commita120143a974668dffea4805a76b61417a8f46a21 (patch)
treedb15d2a47d894128560985edebe7eb23fba04568
parent646b0c13e6235be24a94b57a3e67be81baa25aaf (diff)
Fixed camera streaming not being blocked when user taps camera on personal streaming apps
Root cause: When accessing cross profiles using personal + corp account login, etc., the virtual device always use the user id of the work profile, whether the user launches the personal profile app or the work profile app in app streaming. It will cause a NameNotFoundException to occur and cannot block the camera access when using PackageManager.getApplicationInfo() to query apps that are only installed on the personal profile. Solution: Get all the existing user ids to find out the correct uid of the app that opened the camera, and compare it with the app detected on the virtual display to decide whether to block the camera access. Bug: 245250121 Test: Manual Change-Id: Iea062154ea472d589e5ffc33998698b4b685d7bd
-rw-r--r--services/companion/java/com/android/server/companion/virtual/CameraAccessController.java99
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/companion/virtual/CameraAccessControllerTest.java94
2 files changed, 152 insertions, 41 deletions
diff --git a/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java b/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java
index ec0da490adcf..2904f28fca01 100644
--- a/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java
+++ b/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java
@@ -22,14 +22,19 @@ import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraInjectionSession;
import android.hardware.camera2.CameraManager;
+import android.os.Process;
+import android.os.UserManager;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import java.util.List;
import java.util.Set;
/**
@@ -45,6 +50,7 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
private final CameraAccessBlockedCallback mBlockedCallback;
private final CameraManager mCameraManager;
private final PackageManager mPackageManager;
+ private final UserManager mUserManager;
@GuardedBy("mLock")
private int mObserverCount = 0;
@@ -66,7 +72,7 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
static class OpenCameraInfo {
public String packageName;
- public int packageUid;
+ public Set<Integer> packageUids;
}
interface CameraAccessBlockedCallback {
@@ -85,6 +91,7 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
mBlockedCallback = blockedCallback;
mCameraManager = mContext.getSystemService(CameraManager.class);
mPackageManager = mContext.getPackageManager();
+ mUserManager = mContext.getSystemService(UserManager.class);
}
/**
@@ -125,16 +132,18 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
for (int i = 0; i < mAppsToBlockOnVirtualDevice.size(); i++) {
final String cameraId = mAppsToBlockOnVirtualDevice.keyAt(i);
final OpenCameraInfo openCameraInfo = mAppsToBlockOnVirtualDevice.get(cameraId);
- int packageUid = openCameraInfo.packageUid;
- if (runningUids.contains(packageUid)) {
- final String packageName = openCameraInfo.packageName;
- InjectionSessionData data = mPackageToSessionData.get(packageName);
- if (data == null) {
- data = new InjectionSessionData();
- data.appUid = packageUid;
- mPackageToSessionData.put(packageName, data);
+ final String packageName = openCameraInfo.packageName;
+ for (int packageUid : openCameraInfo.packageUids) {
+ if (runningUids.contains(packageUid)) {
+ InjectionSessionData data = mPackageToSessionData.get(packageName);
+ if (data == null) {
+ data = new InjectionSessionData();
+ data.appUid = packageUid;
+ mPackageToSessionData.put(packageName, data);
+ }
+ startBlocking(packageName, cameraId);
+ break;
}
- startBlocking(packageName, cameraId);
}
}
}
@@ -155,37 +164,41 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
@Override
public void onCameraOpened(@NonNull String cameraId, @NonNull String packageName) {
synchronized (mLock) {
- try {
- final ApplicationInfo ainfo = mPackageManager.getApplicationInfo(packageName, 0);
- InjectionSessionData data = mPackageToSessionData.get(packageName);
- if (!mVirtualDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(ainfo.uid)) {
- OpenCameraInfo openCameraInfo = new OpenCameraInfo();
- openCameraInfo.packageName = packageName;
- openCameraInfo.packageUid = ainfo.uid;
- mAppsToBlockOnVirtualDevice.put(cameraId, openCameraInfo);
- CameraInjectionSession existingSession =
- (data != null) ? data.cameraIdToSession.get(cameraId) : null;
- if (existingSession != null) {
- existingSession.close();
- data.cameraIdToSession.remove(cameraId);
- if (data.cameraIdToSession.isEmpty()) {
- mPackageToSessionData.remove(packageName);
- }
+ InjectionSessionData data = mPackageToSessionData.get(packageName);
+ List<UserInfo> aliveUsers = mUserManager.getAliveUsers();
+ ArraySet<Integer> packageUids = new ArraySet<>();
+ for (UserInfo user : aliveUsers) {
+ int userId = user.getUserHandle().getIdentifier();
+ int appUid = queryUidFromPackageName(userId, packageName);
+ if (mVirtualDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(appUid)) {
+ if (data == null) {
+ data = new InjectionSessionData();
+ data.appUid = appUid;
+ mPackageToSessionData.put(packageName, data);
+ }
+ if (data.cameraIdToSession.containsKey(cameraId)) {
+ return;
}
+ startBlocking(packageName, cameraId);
return;
+ } else {
+ if (appUid != Process.INVALID_UID) {
+ packageUids.add(appUid);
+ }
}
- if (data == null) {
- data = new InjectionSessionData();
- data.appUid = ainfo.uid;
- mPackageToSessionData.put(packageName, data);
- }
- if (data.cameraIdToSession.containsKey(cameraId)) {
- return;
+ }
+ OpenCameraInfo openCameraInfo = new OpenCameraInfo();
+ openCameraInfo.packageName = packageName;
+ openCameraInfo.packageUids = packageUids;
+ mAppsToBlockOnVirtualDevice.put(cameraId, openCameraInfo);
+ CameraInjectionSession existingSession =
+ (data != null) ? data.cameraIdToSession.get(cameraId) : null;
+ if (existingSession != null) {
+ existingSession.close();
+ data.cameraIdToSession.remove(cameraId);
+ if (data.cameraIdToSession.isEmpty()) {
+ mPackageToSessionData.remove(packageName);
}
- startBlocking(packageName, cameraId);
- } catch (PackageManager.NameNotFoundException e) {
- Slog.e(TAG, "onCameraOpened - unknown package " + packageName, e);
- return;
}
}
}
@@ -274,4 +287,16 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
}
}
}
+
+ private int queryUidFromPackageName(int userId, String packageName) {
+ try {
+ final ApplicationInfo ainfo =
+ mPackageManager.getApplicationInfoAsUser(packageName,
+ PackageManager.GET_ACTIVITIES, userId);
+ return ainfo.uid;
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "queryUidFromPackageName - unknown package " + packageName, e);
+ return Process.INVALID_UID;
+ }
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/companion/virtual/CameraAccessControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/companion/virtual/CameraAccessControllerTest.java
index c4c3abc1388e..145e66c92f14 100644
--- a/services/tests/mockingservicestests/src/com/android/server/companion/virtual/CameraAccessControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/companion/virtual/CameraAccessControllerTest.java
@@ -30,10 +30,13 @@ import static org.mockito.Mockito.when;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraInjectionSession;
import android.hardware.camera2.CameraManager;
import android.os.Process;
+import android.os.UserManager;
import android.testing.TestableContext;
import android.util.ArraySet;
@@ -51,12 +54,17 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.List;
+
@RunWith(AndroidJUnit4.class)
public class CameraAccessControllerTest {
private static final String FRONT_CAMERA = "0";
private static final String REAR_CAMERA = "1";
private static final String TEST_APP_PACKAGE = "some.package";
private static final String OTHER_APP_PACKAGE = "other.package";
+ private static final int PERSONAL_PROFILE_USER_ID = 0;
+ private static final int WORK_PROFILE_USER_ID = 10;
private CameraAccessController mController;
@@ -69,6 +77,8 @@ public class CameraAccessControllerTest {
@Mock
private PackageManager mPackageManager;
@Mock
+ private UserManager mUserManager;
+ @Mock
private VirtualDeviceManagerInternal mDeviceManagerInternal;
@Mock
private CameraAccessController.CameraAccessBlockedCallback mBlockedCallback;
@@ -76,6 +86,7 @@ public class CameraAccessControllerTest {
private ApplicationInfo mTestAppInfo = new ApplicationInfo();
private ApplicationInfo mOtherAppInfo = new ApplicationInfo();
private ArraySet<Integer> mRunningUids = new ArraySet<>();
+ private List<UserInfo> mAliveUsers = new ArrayList<>();
@Captor
ArgumentCaptor<CameraInjectionSession.InjectionStatusCallback> mInjectionCallbackCaptor;
@@ -84,6 +95,7 @@ public class CameraAccessControllerTest {
public void setUp() throws PackageManager.NameNotFoundException {
MockitoAnnotations.initMocks(this);
mContext.addMockSystemService(CameraManager.class, mCameraManager);
+ mContext.addMockSystemService(UserManager.class, mUserManager);
mContext.setMockPackageManager(mPackageManager);
LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class);
LocalServices.addService(VirtualDeviceManagerInternal.class, mDeviceManagerInternal);
@@ -92,10 +104,14 @@ public class CameraAccessControllerTest {
mTestAppInfo.uid = Process.FIRST_APPLICATION_UID;
mOtherAppInfo.uid = Process.FIRST_APPLICATION_UID + 1;
mRunningUids.add(Process.FIRST_APPLICATION_UID);
- when(mPackageManager.getApplicationInfo(eq(TEST_APP_PACKAGE), anyInt())).thenReturn(
- mTestAppInfo);
- when(mPackageManager.getApplicationInfo(eq(OTHER_APP_PACKAGE), anyInt())).thenReturn(
- mOtherAppInfo);
+ mAliveUsers.add(new UserInfo(PERSONAL_PROFILE_USER_ID, "", 0));
+ when(mPackageManager.getApplicationInfoAsUser(
+ eq(TEST_APP_PACKAGE), eq(PackageManager.GET_ACTIVITIES),
+ anyInt())).thenReturn(mTestAppInfo);
+ when(mPackageManager.getApplicationInfoAsUser(
+ eq(OTHER_APP_PACKAGE), eq(PackageManager.GET_ACTIVITIES),
+ anyInt())).thenReturn(mOtherAppInfo);
+ when(mUserManager.getAliveUsers()).thenReturn(mAliveUsers);
mController.startObservingIfNeeded();
}
@@ -227,4 +243,74 @@ public class CameraAccessControllerTest {
verify(mCameraManager, times(1)).injectCamera(any(), any(), any(), any(), any());
}
+
+ @Test
+ public void multipleUsers_getPersonalProfileAppUid_cameraBlocked()
+ throws CameraAccessException, NameNotFoundException {
+ mAliveUsers.add(new UserInfo(WORK_PROFILE_USER_ID, "", 0));
+ when(mPackageManager.getApplicationInfoAsUser(
+ eq(TEST_APP_PACKAGE), eq(PackageManager.GET_ACTIVITIES),
+ eq(PERSONAL_PROFILE_USER_ID))).thenReturn(mTestAppInfo);
+ when(mPackageManager.getApplicationInfoAsUser(
+ eq(TEST_APP_PACKAGE), eq(PackageManager.GET_ACTIVITIES),
+ eq(WORK_PROFILE_USER_ID))).thenThrow(NameNotFoundException.class);
+ when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
+ eq(mTestAppInfo.uid))).thenReturn(true);
+ mController.onCameraOpened(FRONT_CAMERA, TEST_APP_PACKAGE);
+
+ verify(mCameraManager).injectCamera(eq(TEST_APP_PACKAGE), eq(FRONT_CAMERA), anyString(),
+ any(), any());
+ }
+
+ @Test
+ public void multipleUsers_getPersonalProfileAppUid_noCameraBlocking()
+ throws CameraAccessException, NameNotFoundException {
+ mAliveUsers.add(new UserInfo(WORK_PROFILE_USER_ID, "", 0));
+ when(mPackageManager.getApplicationInfoAsUser(
+ eq(TEST_APP_PACKAGE), eq(PackageManager.GET_ACTIVITIES),
+ eq(PERSONAL_PROFILE_USER_ID))).thenReturn(mTestAppInfo);
+ when(mPackageManager.getApplicationInfoAsUser(
+ eq(TEST_APP_PACKAGE), eq(PackageManager.GET_ACTIVITIES),
+ eq(WORK_PROFILE_USER_ID))).thenThrow(NameNotFoundException.class);
+ when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
+ eq(mTestAppInfo.uid))).thenReturn(false);
+ mController.onCameraOpened(FRONT_CAMERA, TEST_APP_PACKAGE);
+
+ verify(mCameraManager, never()).injectCamera(any(), any(), any(), any(), any());
+ }
+
+ @Test
+ public void multipleUsers_getWorkProfileAppUid_cameraBlocked()
+ throws CameraAccessException, NameNotFoundException {
+ mAliveUsers.add(new UserInfo(WORK_PROFILE_USER_ID, "", 0));
+ when(mPackageManager.getApplicationInfoAsUser(
+ eq(TEST_APP_PACKAGE), eq(PackageManager.GET_ACTIVITIES),
+ eq(PERSONAL_PROFILE_USER_ID))).thenThrow(NameNotFoundException.class);
+ when(mPackageManager.getApplicationInfoAsUser(
+ eq(TEST_APP_PACKAGE), eq(PackageManager.GET_ACTIVITIES),
+ eq(WORK_PROFILE_USER_ID))).thenReturn(mTestAppInfo);
+ when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
+ eq(mTestAppInfo.uid))).thenReturn(true);
+ mController.onCameraOpened(FRONT_CAMERA, TEST_APP_PACKAGE);
+
+ verify(mCameraManager).injectCamera(eq(TEST_APP_PACKAGE), eq(FRONT_CAMERA), anyString(),
+ any(), any());
+ }
+
+ @Test
+ public void multipleUsers_getWorkProfileAppUid_noCameraBlocking()
+ throws CameraAccessException, NameNotFoundException {
+ mAliveUsers.add(new UserInfo(WORK_PROFILE_USER_ID, "", 0));
+ when(mPackageManager.getApplicationInfoAsUser(
+ eq(TEST_APP_PACKAGE), eq(PackageManager.GET_ACTIVITIES),
+ eq(PERSONAL_PROFILE_USER_ID))).thenThrow(NameNotFoundException.class);
+ when(mPackageManager.getApplicationInfoAsUser(
+ eq(TEST_APP_PACKAGE), eq(PackageManager.GET_ACTIVITIES),
+ eq(WORK_PROFILE_USER_ID))).thenReturn(mTestAppInfo);
+ when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
+ eq(mTestAppInfo.uid))).thenReturn(false);
+ mController.onCameraOpened(FRONT_CAMERA, TEST_APP_PACKAGE);
+
+ verify(mCameraManager, never()).injectCamera(any(), any(), any(), any(), any());
+ }
}