Merge "Fixed camera streaming not being blocked when user taps camera on personal streaming apps" into tm-qpr-dev

This commit is contained in:
Cliff Wu
2022-09-23 00:17:47 +00:00
committed by Android (Google) Code Review
2 changed files with 152 additions and 41 deletions

View File

@@ -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);
}
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);
}
if (data.cameraIdToSession.containsKey(cameraId)) {
return;
}
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;
}
}
}

View File

@@ -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());
}
}