diff options
| author | 2022-09-11 18:20:27 +0800 | |
|---|---|---|
| committer | 2022-09-22 14:20:23 +0000 | |
| commit | a120143a974668dffea4805a76b61417a8f46a21 (patch) | |
| tree | db15d2a47d894128560985edebe7eb23fba04568 | |
| parent | 646b0c13e6235be24a94b57a3e67be81baa25aaf (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
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()); + } } |