diff options
| -rw-r--r-- | services/core/java/com/android/server/biometrics/BiometricCameraManager.java (renamed from services/core/java/com/android/server/biometrics/BiometricSensorPrivacy.java) | 13 | ||||
| -rw-r--r-- | services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java | 68 | ||||
| -rw-r--r-- | services/core/java/com/android/server/biometrics/BiometricSensorPrivacyImpl.java | 37 | ||||
| -rw-r--r-- | services/core/java/com/android/server/biometrics/BiometricService.java | 15 | ||||
| -rw-r--r-- | services/core/java/com/android/server/biometrics/PreAuthInfo.java | 26 | ||||
| -rw-r--r-- | services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java | 4 | ||||
| -rw-r--r-- | services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java | 3 | ||||
| -rw-r--r-- | services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java | 42 |
8 files changed, 141 insertions, 67 deletions
diff --git a/services/core/java/com/android/server/biometrics/BiometricSensorPrivacy.java b/services/core/java/com/android/server/biometrics/BiometricCameraManager.java index 6727fbcdec66..058ea6bbb696 100644 --- a/services/core/java/com/android/server/biometrics/BiometricSensorPrivacy.java +++ b/services/core/java/com/android/server/biometrics/BiometricCameraManager.java @@ -17,9 +17,16 @@ package com.android.server.biometrics; /** - * Interface for biometric operations to get camera privacy state. + * Interface for biometrics to get camera status. */ -public interface BiometricSensorPrivacy { - /* Returns true if privacy is enabled and camera access is disabled. */ +public interface BiometricCameraManager { + /** + * Returns true if any camera is in use. + */ + boolean isAnyCameraUnavailable(); + + /** + * Returns true if privacy is enabled and camera access is disabled. + */ boolean isCameraPrivacyEnabled(); } diff --git a/services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java b/services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java new file mode 100644 index 000000000000..000ee5446962 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.biometrics; + +import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; + +import android.annotation.NonNull; +import android.hardware.SensorPrivacyManager; +import android.hardware.camera2.CameraManager; + +import java.util.concurrent.ConcurrentHashMap; + +public class BiometricCameraManagerImpl implements BiometricCameraManager { + + private final CameraManager mCameraManager; + private final SensorPrivacyManager mSensorPrivacyManager; + private final ConcurrentHashMap<String, Boolean> mIsCameraAvailable = new ConcurrentHashMap<>(); + + private final CameraManager.AvailabilityCallback mCameraAvailabilityCallback = + new CameraManager.AvailabilityCallback() { + @Override + public void onCameraAvailable(@NonNull String cameraId) { + mIsCameraAvailable.put(cameraId, true); + } + + @Override + public void onCameraUnavailable(@NonNull String cameraId) { + mIsCameraAvailable.put(cameraId, false); + } + }; + + public BiometricCameraManagerImpl(@NonNull CameraManager cameraManager, + @NonNull SensorPrivacyManager sensorPrivacyManager) { + mCameraManager = cameraManager; + mSensorPrivacyManager = sensorPrivacyManager; + mCameraManager.registerAvailabilityCallback(mCameraAvailabilityCallback, null); + } + + @Override + public boolean isAnyCameraUnavailable() { + for (String cameraId : mIsCameraAvailable.keySet()) { + if (!mIsCameraAvailable.get(cameraId)) { + return true; + } + } + return false; + } + + @Override + public boolean isCameraPrivacyEnabled() { + return mSensorPrivacyManager != null && mSensorPrivacyManager + .isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE, CAMERA); + } +} diff --git a/services/core/java/com/android/server/biometrics/BiometricSensorPrivacyImpl.java b/services/core/java/com/android/server/biometrics/BiometricSensorPrivacyImpl.java deleted file mode 100644 index b6701da1d348..000000000000 --- a/services/core/java/com/android/server/biometrics/BiometricSensorPrivacyImpl.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.biometrics; - -import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; - -import android.annotation.Nullable; -import android.hardware.SensorPrivacyManager; - -public class BiometricSensorPrivacyImpl implements - BiometricSensorPrivacy { - private final SensorPrivacyManager mSensorPrivacyManager; - - public BiometricSensorPrivacyImpl(@Nullable SensorPrivacyManager sensorPrivacyManager) { - mSensorPrivacyManager = sensorPrivacyManager; - } - - @Override - public boolean isCameraPrivacyEnabled() { - return mSensorPrivacyManager != null && mSensorPrivacyManager - .isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE, CAMERA); - } -} diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index 1fa97a3cb97f..e8ffe4feb458 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -48,6 +48,7 @@ import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; import android.hardware.biometrics.PromptInfo; import android.hardware.biometrics.SensorPropertiesInternal; +import android.hardware.camera2.CameraManager; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.net.Uri; @@ -125,7 +126,7 @@ public class BiometricService extends SystemService { AuthSession mAuthSession; private final Handler mHandler = new Handler(Looper.getMainLooper()); - private final BiometricSensorPrivacy mBiometricSensorPrivacy; + private final BiometricCameraManager mBiometricCameraManager; /** * Tracks authenticatorId invalidation. For more details, see @@ -936,7 +937,7 @@ public class BiometricService extends SystemService { return PreAuthInfo.create(mTrustManager, mDevicePolicyManager, mSettingObserver, mSensors, userId, promptInfo, opPackageName, false /* checkDevicePolicyManager */, - getContext(), mBiometricSensorPrivacy); + getContext(), mBiometricCameraManager); } /** @@ -1030,9 +1031,9 @@ public class BiometricService extends SystemService { return context.getSystemService(UserManager.class); } - public BiometricSensorPrivacy getBiometricSensorPrivacy(Context context) { - return new BiometricSensorPrivacyImpl(context.getSystemService( - SensorPrivacyManager.class)); + public BiometricCameraManager getBiometricCameraManager(Context context) { + return new BiometricCameraManagerImpl(context.getSystemService(CameraManager.class), + context.getSystemService(SensorPrivacyManager.class)); } } @@ -1062,7 +1063,7 @@ public class BiometricService extends SystemService { mRequestCounter = mInjector.getRequestGenerator(); mBiometricContext = injector.getBiometricContext(context); mUserManager = injector.getUserManager(context); - mBiometricSensorPrivacy = injector.getBiometricSensorPrivacy(context); + mBiometricCameraManager = injector.getBiometricCameraManager(context); try { injector.getActivityManagerService().registerUserSwitchObserver( @@ -1299,7 +1300,7 @@ public class BiometricService extends SystemService { final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager, mSettingObserver, mSensors, userId, promptInfo, opPackageName, promptInfo.isDisallowBiometricsIfPolicyExists(), - getContext(), mBiometricSensorPrivacy); + getContext(), mBiometricCameraManager); final Pair<Integer, Integer> preAuthStatus = preAuthInfo.getPreAuthenticateStatus(); diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java index e6f25cb88006..b1740a780539 100644 --- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java +++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java @@ -72,16 +72,16 @@ class PreAuthInfo { final Context context; private final boolean mBiometricRequested; private final int mBiometricStrengthRequested; - private final BiometricSensorPrivacy mBiometricSensorPrivacy; + private final BiometricCameraManager mBiometricCameraManager; private PreAuthInfo(boolean biometricRequested, int biometricStrengthRequested, boolean credentialRequested, List<BiometricSensor> eligibleSensors, List<Pair<BiometricSensor, Integer>> ineligibleSensors, boolean credentialAvailable, boolean confirmationRequested, boolean ignoreEnrollmentState, int userId, - Context context, BiometricSensorPrivacy biometricSensorPrivacy) { + Context context, BiometricCameraManager biometricCameraManager) { mBiometricRequested = biometricRequested; mBiometricStrengthRequested = biometricStrengthRequested; - mBiometricSensorPrivacy = biometricSensorPrivacy; + mBiometricCameraManager = biometricCameraManager; this.credentialRequested = credentialRequested; this.eligibleSensors = eligibleSensors; @@ -99,7 +99,7 @@ class PreAuthInfo { List<BiometricSensor> sensors, int userId, PromptInfo promptInfo, String opPackageName, boolean checkDevicePolicyManager, Context context, - BiometricSensorPrivacy biometricSensorPrivacy) + BiometricCameraManager biometricCameraManager) throws RemoteException { final boolean confirmationRequested = promptInfo.isConfirmationRequested(); @@ -127,7 +127,7 @@ class PreAuthInfo { checkDevicePolicyManager, requestedStrength, promptInfo.getAllowedSensorIds(), promptInfo.isIgnoreEnrollmentState(), - biometricSensorPrivacy); + biometricCameraManager); Slog.d(TAG, "Package: " + opPackageName + " Sensor ID: " + sensor.id @@ -151,7 +151,7 @@ class PreAuthInfo { return new PreAuthInfo(biometricRequested, requestedStrength, credentialRequested, eligibleSensors, ineligibleSensors, credentialAvailable, confirmationRequested, - promptInfo.isIgnoreEnrollmentState(), userId, context, biometricSensorPrivacy); + promptInfo.isIgnoreEnrollmentState(), userId, context, biometricCameraManager); } /** @@ -168,12 +168,16 @@ class PreAuthInfo { BiometricSensor sensor, int userId, String opPackageName, boolean checkDevicePolicyManager, int requestedStrength, @NonNull List<Integer> requestedSensorIds, - boolean ignoreEnrollmentState, BiometricSensorPrivacy biometricSensorPrivacy) { + boolean ignoreEnrollmentState, BiometricCameraManager biometricCameraManager) { if (!requestedSensorIds.isEmpty() && !requestedSensorIds.contains(sensor.id)) { return BIOMETRIC_NO_HARDWARE; } + if (sensor.modality == TYPE_FACE && biometricCameraManager.isAnyCameraUnavailable()) { + return BIOMETRIC_HARDWARE_NOT_DETECTED; + } + final boolean wasStrongEnough = Utils.isAtLeastStrength(sensor.oemStrength, requestedStrength); final boolean isStrongEnough = @@ -195,8 +199,8 @@ class PreAuthInfo { return BIOMETRIC_NOT_ENROLLED; } - if (biometricSensorPrivacy != null && sensor.modality == TYPE_FACE) { - if (biometricSensorPrivacy.isCameraPrivacyEnabled()) { + if (biometricCameraManager != null && sensor.modality == TYPE_FACE) { + if (biometricCameraManager.isCameraPrivacyEnabled()) { //Camera privacy is enabled as the access is disabled return BIOMETRIC_SENSOR_PRIVACY_ENABLED; } @@ -307,8 +311,8 @@ class PreAuthInfo { @BiometricAuthenticator.Modality int modality = TYPE_NONE; boolean cameraPrivacyEnabled = false; - if (mBiometricSensorPrivacy != null) { - cameraPrivacyEnabled = mBiometricSensorPrivacy.isCameraPrivacyEnabled(); + if (mBiometricCameraManager != null) { + cameraPrivacyEnabled = mBiometricCameraManager.isCameraPrivacyEnabled(); } if (mBiometricRequested && credentialRequested) { diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java index 8346050c3c89..0cfddd30d721 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java @@ -106,7 +106,7 @@ public class AuthSessionTest { @Mock private KeyStore mKeyStore; @Mock private AuthSession.ClientDeathReceiver mClientDeathReceiver; @Mock private BiometricFrameworkStatsLogger mBiometricFrameworkStatsLogger; - @Mock BiometricSensorPrivacy mBiometricSensorPrivacy; + @Mock private BiometricCameraManager mBiometricCameraManager; private Random mRandom; private IBinder mToken; @@ -609,7 +609,7 @@ public class AuthSessionTest { TEST_PACKAGE, checkDevicePolicyManager, mContext, - mBiometricSensorPrivacy); + mBiometricCameraManager); } private AuthSession createAuthSession(List<BiometricSensor> sensors, diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java index 41f7dbcb0ff5..68217219e453 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java @@ -151,6 +151,8 @@ public class BiometricServiceTest { private AuthSessionCoordinator mAuthSessionCoordinator; @Mock private UserManager mUserManager; + @Mock + private BiometricCameraManager mBiometricCameraManager; BiometricContextProvider mBiometricContextProvider; @@ -177,6 +179,7 @@ public class BiometricServiceTest { when(mInjector.getDevicePolicyManager(any())).thenReturn(mDevicePolicyManager); when(mInjector.getRequestGenerator()).thenReturn(() -> TEST_REQUEST_ID); when(mInjector.getUserManager(any())).thenReturn(mUserManager); + when(mInjector.getBiometricCameraManager(any())).thenReturn(mBiometricCameraManager); when(mResources.getString(R.string.biometric_error_hw_unavailable)) .thenReturn(ERROR_HW_UNAVAILABLE); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java index 0c98c8d88d83..c2bdf501198e 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java @@ -67,7 +67,7 @@ public class PreAuthInfoTest { @Mock BiometricService.SettingObserver mSettingObserver; @Mock - BiometricSensorPrivacy mBiometricSensorPrivacyUtil; + BiometricCameraManager mBiometricCameraManager; @Before public void setup() throws RemoteException { @@ -79,11 +79,13 @@ public class PreAuthInfoTest { when(mFaceAuthenticator.isHardwareDetected(any())).thenReturn(true); when(mFaceAuthenticator.getLockoutModeForUser(anyInt())) .thenReturn(LOCKOUT_NONE); + when(mBiometricCameraManager.isCameraPrivacyEnabled()).thenReturn(false); + when(mBiometricCameraManager.isAnyCameraUnavailable()).thenReturn(false); } @Test public void testFaceAuthentication_whenCameraPrivacyIsEnabled() throws Exception { - when(mBiometricSensorPrivacyUtil.isCameraPrivacyEnabled()).thenReturn(true); + when(mBiometricCameraManager.isCameraPrivacyEnabled()).thenReturn(true); BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FACE, TYPE_FACE, BiometricManager.Authenticators.BIOMETRIC_STRONG, mFaceAuthenticator) { @@ -104,15 +106,14 @@ public class PreAuthInfoTest { PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager, mSettingObserver, List.of(sensor), 0 /* userId */, promptInfo, TEST_PACKAGE_NAME, - false /* checkDevicePolicyManager */, mContext, mBiometricSensorPrivacyUtil); + false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager); assertThat(preAuthInfo.eligibleSensors).isEmpty(); } @Test - public void testFaceAuthentication_whenCameraPrivacyIsDisabled() throws Exception { - when(mBiometricSensorPrivacyUtil.isCameraPrivacyEnabled()).thenReturn(false); - + public void testFaceAuthentication_whenCameraPrivacyIsDisabledAndCameraIsAvailable() + throws Exception { BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FACE, TYPE_FACE, BiometricManager.Authenticators.BIOMETRIC_STRONG, mFaceAuthenticator) { @Override @@ -132,8 +133,35 @@ public class PreAuthInfoTest { PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager, mSettingObserver, List.of(sensor), 0 /* userId */, promptInfo, TEST_PACKAGE_NAME, - false /* checkDevicePolicyManager */, mContext, mBiometricSensorPrivacyUtil); + false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager); assertThat(preAuthInfo.eligibleSensors).hasSize(1); } + + @Test + public void testFaceAuthentication_whenCameraIsUnavailable() throws RemoteException { + when(mBiometricCameraManager.isAnyCameraUnavailable()).thenReturn(true); + BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FACE, TYPE_FACE, + BiometricManager.Authenticators.BIOMETRIC_STRONG, mFaceAuthenticator) { + @Override + boolean confirmationAlwaysRequired(int userId) { + return false; + } + + @Override + boolean confirmationSupported() { + return false; + } + }; + PromptInfo promptInfo = new PromptInfo(); + promptInfo.setConfirmationRequested(false /* requireConfirmation */); + promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG); + promptInfo.setDisallowBiometricsIfPolicyExists(false /* checkDevicePolicy */); + PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager, + mSettingObserver, List.of(sensor), + 0 /* userId */, promptInfo, TEST_PACKAGE_NAME, + false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager); + + assertThat(preAuthInfo.eligibleSensors).hasSize(0); + } } |