Merge "Fixed camera streaming not being blocked when user taps camera on personal streaming apps" into tm-qpr-dev
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user