Loading services/core/java/com/android/server/biometrics/BiometricSensorPrivacy.java 0 → 100644 +25 −0 Original line number Diff line number Diff line /* * 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; /** * Interface for biometric operations to get camera privacy state. */ public interface BiometricSensorPrivacy { /* Returns true if privacy is enabled and camera access is disabled. */ boolean isCameraPrivacyEnabled(); } services/core/java/com/android/server/biometrics/BiometricSensorPrivacyImpl.java 0 → 100644 +37 −0 Original line number Diff line number Diff line /* * 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); } } services/core/java/com/android/server/biometrics/BiometricService.java +12 −5 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.hardware.SensorPrivacyManager; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricPrompt; Loading Loading @@ -124,6 +125,8 @@ public class BiometricService extends SystemService { AuthSession mAuthSession; private final Handler mHandler = new Handler(Looper.getMainLooper()); private final BiometricSensorPrivacy mBiometricSensorPrivacy; /** * Tracks authenticatorId invalidation. For more details, see * {@link com.android.server.biometrics.sensors.InvalidationRequesterClient}. Loading Loading @@ -933,7 +936,7 @@ public class BiometricService extends SystemService { return PreAuthInfo.create(mTrustManager, mDevicePolicyManager, mSettingObserver, mSensors, userId, promptInfo, opPackageName, false /* checkDevicePolicyManager */, getContext()); getContext(), mBiometricSensorPrivacy); } /** Loading Loading @@ -1026,6 +1029,11 @@ public class BiometricService extends SystemService { public UserManager getUserManager(Context context) { return context.getSystemService(UserManager.class); } public BiometricSensorPrivacy getBiometricSensorPrivacy(Context context) { return new BiometricSensorPrivacyImpl(context.getSystemService( SensorPrivacyManager.class)); } } /** Loading Loading @@ -1054,6 +1062,7 @@ public class BiometricService extends SystemService { mRequestCounter = mInjector.getRequestGenerator(); mBiometricContext = injector.getBiometricContext(context); mUserManager = injector.getUserManager(context); mBiometricSensorPrivacy = injector.getBiometricSensorPrivacy(context); try { injector.getActivityManagerService().registerUserSwitchObserver( Loading Loading @@ -1290,7 +1299,7 @@ public class BiometricService extends SystemService { final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager, mSettingObserver, mSensors, userId, promptInfo, opPackageName, promptInfo.isDisallowBiometricsIfPolicyExists(), getContext()); getContext(), mBiometricSensorPrivacy); final Pair<Integer, Integer> preAuthStatus = preAuthInfo.getPreAuthenticateStatus(); Loading @@ -1300,9 +1309,7 @@ public class BiometricService extends SystemService { + promptInfo.isIgnoreEnrollmentState()); // BIOMETRIC_ERROR_SENSOR_PRIVACY_ENABLED is added so that BiometricPrompt can // be shown for this case. if (preAuthStatus.second == BiometricConstants.BIOMETRIC_SUCCESS || preAuthStatus.second == BiometricConstants.BIOMETRIC_ERROR_SENSOR_PRIVACY_ENABLED) { if (preAuthStatus.second == BiometricConstants.BIOMETRIC_SUCCESS) { // If BIOMETRIC_WEAK or BIOMETRIC_STRONG are allowed, but not enrolled, but // CREDENTIAL is requested and available, set the bundle to only request // CREDENTIAL. Loading services/core/java/com/android/server/biometrics/PreAuthInfo.java +17 −20 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import android.annotation.NonNull; import android.app.admin.DevicePolicyManager; import android.app.trust.ITrustManager; import android.content.Context; import android.hardware.SensorPrivacyManager; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.PromptInfo; Loading Loading @@ -73,13 +72,16 @@ class PreAuthInfo { final Context context; private final boolean mBiometricRequested; private final int mBiometricStrengthRequested; private final BiometricSensorPrivacy mBiometricSensorPrivacy; 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) { Context context, BiometricSensorPrivacy biometricSensorPrivacy) { mBiometricRequested = biometricRequested; mBiometricStrengthRequested = biometricStrengthRequested; mBiometricSensorPrivacy = biometricSensorPrivacy; this.credentialRequested = credentialRequested; this.eligibleSensors = eligibleSensors; Loading @@ -96,7 +98,8 @@ class PreAuthInfo { BiometricService.SettingObserver settingObserver, List<BiometricSensor> sensors, int userId, PromptInfo promptInfo, String opPackageName, boolean checkDevicePolicyManager, Context context) boolean checkDevicePolicyManager, Context context, BiometricSensorPrivacy biometricSensorPrivacy) throws RemoteException { final boolean confirmationRequested = promptInfo.isConfirmationRequested(); Loading Loading @@ -124,7 +127,7 @@ class PreAuthInfo { checkDevicePolicyManager, requestedStrength, promptInfo.getAllowedSensorIds(), promptInfo.isIgnoreEnrollmentState(), context); biometricSensorPrivacy); Slog.d(TAG, "Package: " + opPackageName + " Sensor ID: " + sensor.id Loading @@ -138,7 +141,7 @@ class PreAuthInfo { // // Note: if only a certain sensor is required and the privacy is enabled, // canAuthenticate() will return false. if (status == AUTHENTICATOR_OK || status == BIOMETRIC_SENSOR_PRIVACY_ENABLED) { if (status == AUTHENTICATOR_OK) { eligibleSensors.add(sensor); } else { ineligibleSensors.add(new Pair<>(sensor, status)); Loading @@ -148,7 +151,7 @@ class PreAuthInfo { return new PreAuthInfo(biometricRequested, requestedStrength, credentialRequested, eligibleSensors, ineligibleSensors, credentialAvailable, confirmationRequested, promptInfo.isIgnoreEnrollmentState(), userId, context); promptInfo.isIgnoreEnrollmentState(), userId, context, biometricSensorPrivacy); } /** Loading @@ -165,7 +168,7 @@ class PreAuthInfo { BiometricSensor sensor, int userId, String opPackageName, boolean checkDevicePolicyManager, int requestedStrength, @NonNull List<Integer> requestedSensorIds, boolean ignoreEnrollmentState, Context context) { boolean ignoreEnrollmentState, BiometricSensorPrivacy biometricSensorPrivacy) { if (!requestedSensorIds.isEmpty() && !requestedSensorIds.contains(sensor.id)) { return BIOMETRIC_NO_HARDWARE; Loading @@ -191,12 +194,10 @@ class PreAuthInfo { && !ignoreEnrollmentState) { return BIOMETRIC_NOT_ENROLLED; } final SensorPrivacyManager sensorPrivacyManager = context .getSystemService(SensorPrivacyManager.class); if (sensorPrivacyManager != null && sensor.modality == TYPE_FACE) { if (sensorPrivacyManager .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, userId)) { if (biometricSensorPrivacy != null && sensor.modality == TYPE_FACE) { if (biometricSensorPrivacy.isCameraPrivacyEnabled()) { //Camera privacy is enabled as the access is disabled return BIOMETRIC_SENSOR_PRIVACY_ENABLED; } } Loading Loading @@ -292,13 +293,9 @@ class PreAuthInfo { @AuthenticatorStatus final int status; @BiometricAuthenticator.Modality int modality = TYPE_NONE; final SensorPrivacyManager sensorPrivacyManager = context .getSystemService(SensorPrivacyManager.class); boolean cameraPrivacyEnabled = false; if (sensorPrivacyManager != null) { cameraPrivacyEnabled = sensorPrivacyManager .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, userId); if (mBiometricSensorPrivacy != null) { cameraPrivacyEnabled = mBiometricSensorPrivacy.isCameraPrivacyEnabled(); } if (mBiometricRequested && credentialRequested) { Loading @@ -315,7 +312,7 @@ class PreAuthInfo { // and the face sensor privacy is enabled then return // BIOMETRIC_SENSOR_PRIVACY_ENABLED. // // Note: This sensor will still be eligible for calls to authenticate. // Note: This sensor will not be eligible for calls to authenticate. status = BIOMETRIC_SENSOR_PRIVACY_ENABLED; } else { status = AUTHENTICATOR_OK; Loading @@ -340,7 +337,7 @@ class PreAuthInfo { // If the only modality requested is face and the privacy is enabled // then return BIOMETRIC_SENSOR_PRIVACY_ENABLED. // // Note: This sensor will still be eligible for calls to authenticate. // Note: This sensor will not be eligible for calls to authenticate. status = BIOMETRIC_SENSOR_PRIVACY_ENABLED; } else { status = AUTHENTICATOR_OK; Loading services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java +3 −1 Original line number Diff line number Diff line Loading @@ -104,6 +104,7 @@ public class AuthSessionTest { @Mock private KeyStore mKeyStore; @Mock private AuthSession.ClientDeathReceiver mClientDeathReceiver; @Mock private BiometricFrameworkStatsLogger mBiometricFrameworkStatsLogger; @Mock BiometricSensorPrivacy mBiometricSensorPrivacy; private Random mRandom; private IBinder mToken; Loading Loading @@ -571,7 +572,8 @@ public class AuthSessionTest { promptInfo, TEST_PACKAGE, checkDevicePolicyManager, mContext); mContext, mBiometricSensorPrivacy); } private AuthSession createAuthSession(List<BiometricSensor> sensors, Loading Loading
services/core/java/com/android/server/biometrics/BiometricSensorPrivacy.java 0 → 100644 +25 −0 Original line number Diff line number Diff line /* * 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; /** * Interface for biometric operations to get camera privacy state. */ public interface BiometricSensorPrivacy { /* Returns true if privacy is enabled and camera access is disabled. */ boolean isCameraPrivacyEnabled(); }
services/core/java/com/android/server/biometrics/BiometricSensorPrivacyImpl.java 0 → 100644 +37 −0 Original line number Diff line number Diff line /* * 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); } }
services/core/java/com/android/server/biometrics/BiometricService.java +12 −5 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.hardware.SensorPrivacyManager; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricPrompt; Loading Loading @@ -124,6 +125,8 @@ public class BiometricService extends SystemService { AuthSession mAuthSession; private final Handler mHandler = new Handler(Looper.getMainLooper()); private final BiometricSensorPrivacy mBiometricSensorPrivacy; /** * Tracks authenticatorId invalidation. For more details, see * {@link com.android.server.biometrics.sensors.InvalidationRequesterClient}. Loading Loading @@ -933,7 +936,7 @@ public class BiometricService extends SystemService { return PreAuthInfo.create(mTrustManager, mDevicePolicyManager, mSettingObserver, mSensors, userId, promptInfo, opPackageName, false /* checkDevicePolicyManager */, getContext()); getContext(), mBiometricSensorPrivacy); } /** Loading Loading @@ -1026,6 +1029,11 @@ public class BiometricService extends SystemService { public UserManager getUserManager(Context context) { return context.getSystemService(UserManager.class); } public BiometricSensorPrivacy getBiometricSensorPrivacy(Context context) { return new BiometricSensorPrivacyImpl(context.getSystemService( SensorPrivacyManager.class)); } } /** Loading Loading @@ -1054,6 +1062,7 @@ public class BiometricService extends SystemService { mRequestCounter = mInjector.getRequestGenerator(); mBiometricContext = injector.getBiometricContext(context); mUserManager = injector.getUserManager(context); mBiometricSensorPrivacy = injector.getBiometricSensorPrivacy(context); try { injector.getActivityManagerService().registerUserSwitchObserver( Loading Loading @@ -1290,7 +1299,7 @@ public class BiometricService extends SystemService { final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager, mSettingObserver, mSensors, userId, promptInfo, opPackageName, promptInfo.isDisallowBiometricsIfPolicyExists(), getContext()); getContext(), mBiometricSensorPrivacy); final Pair<Integer, Integer> preAuthStatus = preAuthInfo.getPreAuthenticateStatus(); Loading @@ -1300,9 +1309,7 @@ public class BiometricService extends SystemService { + promptInfo.isIgnoreEnrollmentState()); // BIOMETRIC_ERROR_SENSOR_PRIVACY_ENABLED is added so that BiometricPrompt can // be shown for this case. if (preAuthStatus.second == BiometricConstants.BIOMETRIC_SUCCESS || preAuthStatus.second == BiometricConstants.BIOMETRIC_ERROR_SENSOR_PRIVACY_ENABLED) { if (preAuthStatus.second == BiometricConstants.BIOMETRIC_SUCCESS) { // If BIOMETRIC_WEAK or BIOMETRIC_STRONG are allowed, but not enrolled, but // CREDENTIAL is requested and available, set the bundle to only request // CREDENTIAL. Loading
services/core/java/com/android/server/biometrics/PreAuthInfo.java +17 −20 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import android.annotation.NonNull; import android.app.admin.DevicePolicyManager; import android.app.trust.ITrustManager; import android.content.Context; import android.hardware.SensorPrivacyManager; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.PromptInfo; Loading Loading @@ -73,13 +72,16 @@ class PreAuthInfo { final Context context; private final boolean mBiometricRequested; private final int mBiometricStrengthRequested; private final BiometricSensorPrivacy mBiometricSensorPrivacy; 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) { Context context, BiometricSensorPrivacy biometricSensorPrivacy) { mBiometricRequested = biometricRequested; mBiometricStrengthRequested = biometricStrengthRequested; mBiometricSensorPrivacy = biometricSensorPrivacy; this.credentialRequested = credentialRequested; this.eligibleSensors = eligibleSensors; Loading @@ -96,7 +98,8 @@ class PreAuthInfo { BiometricService.SettingObserver settingObserver, List<BiometricSensor> sensors, int userId, PromptInfo promptInfo, String opPackageName, boolean checkDevicePolicyManager, Context context) boolean checkDevicePolicyManager, Context context, BiometricSensorPrivacy biometricSensorPrivacy) throws RemoteException { final boolean confirmationRequested = promptInfo.isConfirmationRequested(); Loading Loading @@ -124,7 +127,7 @@ class PreAuthInfo { checkDevicePolicyManager, requestedStrength, promptInfo.getAllowedSensorIds(), promptInfo.isIgnoreEnrollmentState(), context); biometricSensorPrivacy); Slog.d(TAG, "Package: " + opPackageName + " Sensor ID: " + sensor.id Loading @@ -138,7 +141,7 @@ class PreAuthInfo { // // Note: if only a certain sensor is required and the privacy is enabled, // canAuthenticate() will return false. if (status == AUTHENTICATOR_OK || status == BIOMETRIC_SENSOR_PRIVACY_ENABLED) { if (status == AUTHENTICATOR_OK) { eligibleSensors.add(sensor); } else { ineligibleSensors.add(new Pair<>(sensor, status)); Loading @@ -148,7 +151,7 @@ class PreAuthInfo { return new PreAuthInfo(biometricRequested, requestedStrength, credentialRequested, eligibleSensors, ineligibleSensors, credentialAvailable, confirmationRequested, promptInfo.isIgnoreEnrollmentState(), userId, context); promptInfo.isIgnoreEnrollmentState(), userId, context, biometricSensorPrivacy); } /** Loading @@ -165,7 +168,7 @@ class PreAuthInfo { BiometricSensor sensor, int userId, String opPackageName, boolean checkDevicePolicyManager, int requestedStrength, @NonNull List<Integer> requestedSensorIds, boolean ignoreEnrollmentState, Context context) { boolean ignoreEnrollmentState, BiometricSensorPrivacy biometricSensorPrivacy) { if (!requestedSensorIds.isEmpty() && !requestedSensorIds.contains(sensor.id)) { return BIOMETRIC_NO_HARDWARE; Loading @@ -191,12 +194,10 @@ class PreAuthInfo { && !ignoreEnrollmentState) { return BIOMETRIC_NOT_ENROLLED; } final SensorPrivacyManager sensorPrivacyManager = context .getSystemService(SensorPrivacyManager.class); if (sensorPrivacyManager != null && sensor.modality == TYPE_FACE) { if (sensorPrivacyManager .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, userId)) { if (biometricSensorPrivacy != null && sensor.modality == TYPE_FACE) { if (biometricSensorPrivacy.isCameraPrivacyEnabled()) { //Camera privacy is enabled as the access is disabled return BIOMETRIC_SENSOR_PRIVACY_ENABLED; } } Loading Loading @@ -292,13 +293,9 @@ class PreAuthInfo { @AuthenticatorStatus final int status; @BiometricAuthenticator.Modality int modality = TYPE_NONE; final SensorPrivacyManager sensorPrivacyManager = context .getSystemService(SensorPrivacyManager.class); boolean cameraPrivacyEnabled = false; if (sensorPrivacyManager != null) { cameraPrivacyEnabled = sensorPrivacyManager .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, userId); if (mBiometricSensorPrivacy != null) { cameraPrivacyEnabled = mBiometricSensorPrivacy.isCameraPrivacyEnabled(); } if (mBiometricRequested && credentialRequested) { Loading @@ -315,7 +312,7 @@ class PreAuthInfo { // and the face sensor privacy is enabled then return // BIOMETRIC_SENSOR_PRIVACY_ENABLED. // // Note: This sensor will still be eligible for calls to authenticate. // Note: This sensor will not be eligible for calls to authenticate. status = BIOMETRIC_SENSOR_PRIVACY_ENABLED; } else { status = AUTHENTICATOR_OK; Loading @@ -340,7 +337,7 @@ class PreAuthInfo { // If the only modality requested is face and the privacy is enabled // then return BIOMETRIC_SENSOR_PRIVACY_ENABLED. // // Note: This sensor will still be eligible for calls to authenticate. // Note: This sensor will not be eligible for calls to authenticate. status = BIOMETRIC_SENSOR_PRIVACY_ENABLED; } else { status = AUTHENTICATOR_OK; Loading
services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java +3 −1 Original line number Diff line number Diff line Loading @@ -104,6 +104,7 @@ public class AuthSessionTest { @Mock private KeyStore mKeyStore; @Mock private AuthSession.ClientDeathReceiver mClientDeathReceiver; @Mock private BiometricFrameworkStatsLogger mBiometricFrameworkStatsLogger; @Mock BiometricSensorPrivacy mBiometricSensorPrivacy; private Random mRandom; private IBinder mToken; Loading Loading @@ -571,7 +572,8 @@ public class AuthSessionTest { promptInfo, TEST_PACKAGE, checkDevicePolicyManager, mContext); mContext, mBiometricSensorPrivacy); } private AuthSession createAuthSession(List<BiometricSensor> sensors, Loading