diff options
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()); + } } |