diff options
60 files changed, 986 insertions, 339 deletions
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 27027721109d..08e95a267d7f 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3195,7 +3195,7 @@ public abstract class Context { * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#O} * or higher are not allowed to start background services from the background. * See - * <a href="{@docRoot}/about/versions/oreo/background"> + * <a href="/about/versions/oreo/background"> * Background Execution Limits</a> * for more details. * @@ -3204,7 +3204,7 @@ public abstract class Context { * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S} * or higher are not allowed to start foreground services from the background. * See - * <a href="{@docRoot}/about/versions/12/behavior-changes-12"> + * <a href="/about/versions/12/behavior-changes-12"> * Behavior changes: Apps targeting Android 12 * </a> * for more details. @@ -3258,7 +3258,7 @@ public abstract class Context { * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S} * or higher are not allowed to start foreground services from the background. * See - * <a href="{@docRoot}/about/versions/12/behavior-changes-12"> + * <a href="/about/versions/12/behavior-changes-12"> * Behavior changes: Apps targeting Android 12 * </a> * for more details. diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java index 3f3db29ed0fd..c8c122da4ab8 100644 --- a/core/java/android/hardware/biometrics/BiometricPrompt.java +++ b/core/java/android/hardware/biometrics/BiometricPrompt.java @@ -438,9 +438,16 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan } private class OnAuthenticationCancelListener implements CancellationSignal.OnCancelListener { + private final long mAuthRequestId; + + OnAuthenticationCancelListener(long id) { + mAuthRequestId = id; + } + @Override public void onCancel() { - cancelAuthentication(); + Log.d(TAG, "Cancel BP authentication requested for: " + mAuthRequestId); + cancelAuthentication(mAuthRequestId); } } @@ -853,10 +860,12 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan * @param userId The user to authenticate * @param operationId The keystore operation associated with authentication * + * @return A requestId that can be used to cancel this operation. + * * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) - public void authenticateUserForOperation( + public long authenticateUserForOperation( @NonNull CancellationSignal cancel, @NonNull @CallbackExecutor Executor executor, @NonNull AuthenticationCallback callback, @@ -871,7 +880,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan if (callback == null) { throw new IllegalArgumentException("Must supply a callback"); } - authenticateInternal(operationId, cancel, executor, callback, userId); + + return authenticateInternal(operationId, cancel, executor, callback, userId); } /** @@ -1002,10 +1012,10 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan authenticateInternal(null /* crypto */, cancel, executor, callback, mContext.getUserId()); } - private void cancelAuthentication() { + private void cancelAuthentication(long requestId) { if (mService != null) { try { - mService.cancelAuthentication(mToken, mContext.getOpPackageName()); + mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId); } catch (RemoteException e) { Log.e(TAG, "Unable to cancel authentication", e); } @@ -1024,7 +1034,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan authenticateInternal(operationId, cancel, executor, callback, userId); } - private void authenticateInternal( + private long authenticateInternal( long operationId, @NonNull CancellationSignal cancel, @NonNull @CallbackExecutor Executor executor, @@ -1040,9 +1050,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan try { if (cancel.isCanceled()) { Log.w(TAG, "Authentication already canceled"); - return; - } else { - cancel.setOnCancelListener(new OnAuthenticationCancelListener()); + return -1; } mExecutor = executor; @@ -1065,14 +1073,16 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan promptInfo = mPromptInfo; } - mService.authenticate(mToken, operationId, userId, mBiometricServiceReceiver, - mContext.getOpPackageName(), promptInfo); - + final long authId = mService.authenticate(mToken, operationId, userId, + mBiometricServiceReceiver, mContext.getOpPackageName(), promptInfo); + cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId)); + return authId; } catch (RemoteException e) { Log.e(TAG, "Remote exception while authenticating", e); mExecutor.execute(() -> callback.onAuthenticationError( BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE, mContext.getString(R.string.biometric_error_hw_unavailable))); + return -1; } } diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl index 4c2a9ae10cbd..91f794c161bf 100644 --- a/core/java/android/hardware/biometrics/IAuthService.aidl +++ b/core/java/android/hardware/biometrics/IAuthService.aidl @@ -41,13 +41,14 @@ interface IAuthService { // Retrieve the package where BIometricOrompt's UI is implemented String getUiPackage(); - // Requests authentication. The service choose the appropriate biometric to use, and show - // the corresponding BiometricDialog. - void authenticate(IBinder token, long sessionId, int userId, + // Requests authentication. The service chooses the appropriate biometric to use, and shows + // the corresponding BiometricDialog. A requestId is returned that can be used to cancel + // this operation. + long authenticate(IBinder token, long sessionId, int userId, IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo); - // Cancel authentication for the given sessionId - void cancelAuthentication(IBinder token, String opPackageName); + // Cancel authentication for the given requestId. + void cancelAuthentication(IBinder token, String opPackageName, long requestId); // TODO(b/141025588): Make userId the first arg to be consistent with hasEnrolledBiometrics. // Checks if biometrics can be used. diff --git a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl index 876513f266e8..addd622eef35 100644 --- a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl +++ b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl @@ -48,13 +48,13 @@ interface IBiometricAuthenticator { // startPreparedClient(). void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, - int cookie, boolean allowBackgroundAuthentication); + long requestId, int cookie, boolean allowBackgroundAuthentication); // Starts authentication with the previously prepared client. void startPreparedClient(int cookie); - // Cancels authentication. - void cancelAuthenticationFromService(IBinder token, String opPackageName); + // Cancels authentication for the given requestId. + void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId); // Determine if HAL is loaded and ready boolean isHardwareDetected(String opPackageName); diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl index 64b51183a170..2c3c8c353e8c 100644 --- a/core/java/android/hardware/biometrics/IBiometricService.aidl +++ b/core/java/android/hardware/biometrics/IBiometricService.aidl @@ -36,13 +36,14 @@ interface IBiometricService { // Retrieve static sensor properties for all biometric sensors List<SensorPropertiesInternal> getSensorProperties(String opPackageName); - // Requests authentication. The service choose the appropriate biometric to use, and show - // the corresponding BiometricDialog. - void authenticate(IBinder token, long operationId, int userId, + // Requests authentication. The service chooses the appropriate biometric to use, and shows + // the corresponding BiometricDialog. A requestId is returned that can be used to cancel + // this operation. + long authenticate(IBinder token, long operationId, int userId, IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo); - // Cancel authentication for the given session. - void cancelAuthentication(IBinder token, String opPackageName); + // Cancel authentication for the given requestId. + void cancelAuthentication(IBinder token, String opPackageName, long requestId); // Checks if biometrics can be used. int canAuthenticate(String opPackageName, int userId, int callingUserId, int authenticators); diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index 385ad2d3577f..56f81423db4e 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -58,7 +58,7 @@ import java.util.List; public class FaceManager implements BiometricAuthenticator, BiometricFaceConstants { private static final String TAG = "FaceManager"; - private static final boolean DEBUG = true; + private static final int MSG_ENROLL_RESULT = 100; private static final int MSG_ACQUIRED = 101; private static final int MSG_AUTHENTICATION_SUCCEEDED = 102; @@ -207,13 +207,9 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan throw new IllegalArgumentException("Must supply an authentication callback"); } - if (cancel != null) { - if (cancel.isCanceled()) { - Slog.w(TAG, "authentication already canceled"); - return; - } else { - cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto)); - } + if (cancel != null && cancel.isCanceled()) { + Slog.w(TAG, "authentication already canceled"); + return; } if (mService != null) { @@ -223,17 +219,18 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan mCryptoObject = crypto; final long operationId = crypto != null ? crypto.getOpId() : 0; Trace.beginSection("FaceManager#authenticate"); - mService.authenticate(mToken, operationId, userId, mServiceReceiver, - mContext.getOpPackageName(), isKeyguardBypassEnabled); + final long authId = mService.authenticate(mToken, operationId, userId, + mServiceReceiver, mContext.getOpPackageName(), isKeyguardBypassEnabled); + if (cancel != null) { + cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId)); + } } catch (RemoteException e) { Slog.w(TAG, "Remote exception while authenticating: ", e); - if (callback != null) { - // Though this may not be a hardware issue, it will cause apps to give up or - // try again later. - callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE, - getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE, - 0 /* vendorCode */)); - } + // Though this may not be a hardware issue, it will cause apps to give up or + // try again later. + callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE, + getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE, + 0 /* vendorCode */)); } finally { Trace.endSection(); } @@ -255,14 +252,14 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan if (cancel.isCanceled()) { Slog.w(TAG, "Detection already cancelled"); return; - } else { - cancel.setOnCancelListener(new OnFaceDetectionCancelListener()); } mFaceDetectionCallback = callback; try { - mService.detectFace(mToken, userId, mServiceReceiver, mContext.getOpPackageName()); + final long authId = mService.detectFace( + mToken, userId, mServiceReceiver, mContext.getOpPackageName()); + cancel.setOnCancelListener(new OnFaceDetectionCancelListener(authId)); } catch (RemoteException e) { Slog.w(TAG, "Remote exception when requesting finger detect", e); } @@ -726,23 +723,23 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan } } - private void cancelAuthentication(CryptoObject cryptoObject) { + private void cancelAuthentication(long requestId) { if (mService != null) { try { - mService.cancelAuthentication(mToken, mContext.getOpPackageName()); + mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } - private void cancelFaceDetect() { + private void cancelFaceDetect(long requestId) { if (mService == null) { return; } try { - mService.cancelFaceDetect(mToken, mContext.getOpPackageName()); + mService.cancelFaceDetect(mToken, mContext.getOpPackageName(), requestId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -794,9 +791,9 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan // This is used as a last resort in case a vendor string is missing // It should not happen for anything other than FACE_ERROR_VENDOR, but // warn and use the default if all else fails. - // TODO(b/196639965): update string Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode); - return ""; + return context.getString( + com.android.internal.R.string.face_error_vendor_unknown); } /** @@ -1110,22 +1107,30 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan } private class OnAuthenticationCancelListener implements OnCancelListener { - private final CryptoObject mCrypto; + private final long mAuthRequestId; - OnAuthenticationCancelListener(CryptoObject crypto) { - mCrypto = crypto; + OnAuthenticationCancelListener(long id) { + mAuthRequestId = id; } @Override public void onCancel() { - cancelAuthentication(mCrypto); + Slog.d(TAG, "Cancel face authentication requested for: " + mAuthRequestId); + cancelAuthentication(mAuthRequestId); } } private class OnFaceDetectionCancelListener implements OnCancelListener { + private final long mAuthRequestId; + + OnFaceDetectionCancelListener(long id) { + mAuthRequestId = id; + } + @Override public void onCancel() { - cancelFaceDetect(); + Slog.d(TAG, "Cancel face detect requested for: " + mAuthRequestId); + cancelFaceDetect(mAuthRequestId); } } diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl index db02a0ef2a10..e9198246dee3 100644 --- a/core/java/android/hardware/face/IFaceService.aidl +++ b/core/java/android/hardware/face/IFaceService.aidl @@ -44,34 +44,36 @@ interface IFaceService { // Retrieve static sensor properties for the specified sensor FaceSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName); - // Authenticate the given sessionId with a face - void authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver, + // Authenticate with a face. A requestId is returned that can be used to cancel this operation. + long authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver, String opPackageName, boolean isKeyguardBypassEnabled); // Uses the face hardware to detect for the presence of a face, without giving details - // about accept/reject/lockout. - void detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName); + // about accept/reject/lockout. A requestId is returned that can be used to cancel this + // operation. + long detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName); // This method prepares the service to start authenticating, but doesn't start authentication. // This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be // called from BiometricService. The additional uid, pid, userId arguments should be determined // by BiometricService. To start authentication after the clients are ready, use // startPreparedClient(). - void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, long operationId, - int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, - int cookie, boolean allowBackgroundAuthentication); + void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, + long operationId, int userId, IBiometricSensorReceiver sensorReceiver, + String opPackageName, long requestId, int cookie, + boolean allowBackgroundAuthentication); // Starts authentication with the previously prepared client. void startPreparedClient(int sensorId, int cookie); - // Cancel authentication for the given sessionId - void cancelAuthentication(IBinder token, String opPackageName); + // Cancel authentication for the given requestId. + void cancelAuthentication(IBinder token, String opPackageName, long requestId); - // Cancel face detection - void cancelFaceDetect(IBinder token, String opPackageName); + // Cancel face detection for the given requestId. + void cancelFaceDetect(IBinder token, String opPackageName, long requestId); // Same as above, with extra arguments. - void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName); + void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName, long requestId); // Start face enrollment void enroll(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver, diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 87d45b9de745..7c42dc0da7c7 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -189,22 +189,30 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } private class OnAuthenticationCancelListener implements OnCancelListener { - private android.hardware.biometrics.CryptoObject mCrypto; + private final long mAuthRequestId; - public OnAuthenticationCancelListener(android.hardware.biometrics.CryptoObject crypto) { - mCrypto = crypto; + OnAuthenticationCancelListener(long id) { + mAuthRequestId = id; } @Override public void onCancel() { - cancelAuthentication(mCrypto); + Slog.d(TAG, "Cancel fingerprint authentication requested for: " + mAuthRequestId); + cancelAuthentication(mAuthRequestId); } } private class OnFingerprintDetectionCancelListener implements OnCancelListener { + private final long mAuthRequestId; + + OnFingerprintDetectionCancelListener(long id) { + mAuthRequestId = id; + } + @Override public void onCancel() { - cancelFingerprintDetect(); + Slog.d(TAG, "Cancel fingerprint detect requested for: " + mAuthRequestId); + cancelFingerprintDetect(mAuthRequestId); } } @@ -552,13 +560,9 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing throw new IllegalArgumentException("Must supply an authentication callback"); } - if (cancel != null) { - if (cancel.isCanceled()) { - Slog.w(TAG, "authentication already canceled"); - return; - } else { - cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto)); - } + if (cancel != null && cancel.isCanceled()) { + Slog.w(TAG, "authentication already canceled"); + return; } if (mService != null) { @@ -567,8 +571,11 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing mAuthenticationCallback = callback; mCryptoObject = crypto; final long operationId = crypto != null ? crypto.getOpId() : 0; - mService.authenticate(mToken, operationId, sensorId, userId, mServiceReceiver, - mContext.getOpPackageName()); + final long authId = mService.authenticate(mToken, operationId, sensorId, userId, + mServiceReceiver, mContext.getOpPackageName()); + if (cancel != null) { + cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId)); + } } catch (RemoteException e) { Slog.w(TAG, "Remote exception while authenticating: ", e); // Though this may not be a hardware issue, it will cause apps to give up or try @@ -595,15 +602,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing if (cancel.isCanceled()) { Slog.w(TAG, "Detection already cancelled"); return; - } else { - cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener()); } mFingerprintDetectionCallback = callback; try { - mService.detectFingerprint(mToken, userId, mServiceReceiver, + final long authId = mService.detectFingerprint(mToken, userId, mServiceReceiver, mContext.getOpPackageName()); + cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener(authId)); } catch (RemoteException e) { Slog.w(TAG, "Remote exception when requesting finger detect", e); } @@ -1320,21 +1326,21 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } } - private void cancelAuthentication(android.hardware.biometrics.CryptoObject cryptoObject) { + private void cancelAuthentication(long requestId) { if (mService != null) try { - mService.cancelAuthentication(mToken, mContext.getOpPackageName()); + mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } - private void cancelFingerprintDetect() { + private void cancelFingerprintDetect(long requestId) { if (mService == null) { return; } try { - mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName()); + mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName(), requestId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1390,9 +1396,9 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing // This is used as a last resort in case a vendor string is missing // It should not happen for anything other than FINGERPRINT_ERROR_VENDOR, but // warn and use the default if all else fails. - // TODO(b/196639965): update string Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode); - return ""; + return context.getString( + com.android.internal.R.string.fingerprint_error_vendor_unknown); } /** diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 3979afe80d17..477482757699 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -48,15 +48,16 @@ interface IFingerprintService { // Retrieve static sensor properties for the specified sensor FingerprintSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName); - // Authenticate the given sessionId with a fingerprint. This is protected by - // USE_FINGERPRINT/USE_BIOMETRIC permission. This is effectively deprecated, since it only comes - // through FingerprintManager now. - void authenticate(IBinder token, long operationId, int sensorId, int userId, + // Authenticate with a fingerprint. This is protected by USE_FINGERPRINT/USE_BIOMETRIC + // permission. This is effectively deprecated, since it only comes through FingerprintManager + // now. A requestId is returned that can be used to cancel this operation. + long authenticate(IBinder token, long operationId, int sensorId, int userId, IFingerprintServiceReceiver receiver, String opPackageName); // Uses the fingerprint hardware to detect for the presence of a finger, without giving details - // about accept/reject/lockout. - void detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver, + // about accept/reject/lockout. A requestId is returned that can be used to cancel this + // operation. + long detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver, String opPackageName); // This method prepares the service to start authenticating, but doesn't start authentication. @@ -65,21 +66,21 @@ interface IFingerprintService { // by BiometricService. To start authentication after the clients are ready, use // startPreparedClient(). void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId, - IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie, - boolean allowBackgroundAuthentication); + IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId, + int cookie, boolean allowBackgroundAuthentication); // Starts authentication with the previously prepared client. void startPreparedClient(int sensorId, int cookie); - // Cancel authentication for the given sessionId - void cancelAuthentication(IBinder token, String opPackageName); + // Cancel authentication for the given requestId. + void cancelAuthentication(IBinder token, String opPackageName, long requestId); - // Cancel finger detection - void cancelFingerprintDetect(IBinder token, String opPackageName); + // Cancel finger detection for the given requestId. + void cancelFingerprintDetect(IBinder token, String opPackageName, long requestId); // Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes // an additional uid, pid, userid. - void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName); + void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName, long requestId); // Start fingerprint enrollment void enroll(IBinder token, in byte [] hardwareAuthToken, int userId, IFingerprintServiceReceiver receiver, diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 10f14b42ae42..ed6415d749a3 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -148,7 +148,7 @@ oneway interface IStatusBar */ void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver, in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId, - String opPackageName, long operationId, int multiSensorConfig); + long operationId, String opPackageName, long requestId, int multiSensorConfig); /** * Used to notify the authentication dialog that a biometric has been authenticated. */ diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index e7d6d6cf8936..b3499db94c88 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -110,7 +110,8 @@ interface IStatusBarService // Used to show the authentication dialog (Biometrics, Device Credential) void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver, in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, - int userId, String opPackageName, long operationId, int multiSensorConfig); + int userId, long operationId, String opPackageName, long requestId, + int multiSensorConfig); // Used to notify the authentication dialog that a biometric has been authenticated void onBiometricAuthenticated(); diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index a99a22009e3b..b58638cc3ade 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1650,6 +1650,8 @@ <!-- Array containing custom error messages from vendor. Vendor is expected to add and translate these strings --> <string-array name="fingerprint_error_vendor"> </string-array> + <!-- Default error message to use when fingerprint_error_vendor does not contain a message. [CHAR LIMIT=NONE] --> + <string name="fingerprint_error_vendor_unknown">Something went wrong. Try again.</string> <!-- Content description which should be used for the fingerprint icon. --> <string name="fingerprint_icon_content_description">Fingerprint icon</string> @@ -1760,6 +1762,8 @@ <!-- Array containing custom error messages from vendor. Vendor is expected to add and translate these strings --> <string-array name="face_error_vendor"> </string-array> + <!-- Default error message to use when face_error_vendor does not contain a message. [CHAR LIMIT=NONE] --> + <string name="face_error_vendor_unknown">Something went wrong. Try again.</string> <!-- Content description which should be used for the face icon. [CHAR LIMIT=10] --> <string name="face_icon_content_description">Face icon</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 6802ae551e82..7799b8eb2fb2 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2525,6 +2525,7 @@ <java-symbol type="string" name="fingerprint_error_no_space" /> <java-symbol type="string" name="fingerprint_error_timeout" /> <java-symbol type="array" name="fingerprint_error_vendor" /> + <java-symbol type="string" name="fingerprint_error_vendor_unknown" /> <java-symbol type="string" name="fingerprint_acquired_partial" /> <java-symbol type="string" name="fingerprint_acquired_insufficient" /> <java-symbol type="string" name="fingerprint_acquired_imager_dirty" /> @@ -2564,6 +2565,7 @@ <java-symbol type="string" name="face_error_no_space" /> <java-symbol type="string" name="face_error_timeout" /> <java-symbol type="array" name="face_error_vendor" /> + <java-symbol type="string" name="face_error_vendor_unknown" /> <java-symbol type="string" name="face_error_canceled" /> <java-symbol type="string" name="face_error_user_canceled" /> <java-symbol type="string" name="face_error_lockout" /> diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java index 5f107d662b75..34e7e3d1cd6b 100644 --- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java +++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java @@ -84,8 +84,7 @@ public class MDNSFilterPlugin implements PrintServicePlugin { */ public MDNSFilterPlugin(@NonNull Context context, @NonNull String name, @NonNull CharSequence packageName, @NonNull List<String> mDNSNames) { - mName = context.getResources().getIdentifier(name, null, - "com.android.printservice.recommendation"); + mName = context.getResources().getIdentifier(name, null, context.getPackageName()); mPackageName = packageName; mMDNSFilteredDiscovery = new MDNSFilteredDiscovery(context, PRINTER_SERVICE_TYPES, new VendorNameFilter(new HashSet<>(mDNSNames))); diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 3b1f4fde109a..19633f2492cf 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -187,7 +187,8 @@ <!-- UDFPS colors --> <color name="udfps_enroll_icon">#000000</color> <!-- 100% black --> <color name="udfps_moving_target_fill">#cc4285f4</color> <!-- 80% blue --> - <color name="udfps_enroll_progress">#ff669DF6</color> <!-- 100% blue --> + <color name="udfps_enroll_progress">#ff669DF6</color> <!-- blue 400 --> + <color name="udfps_enroll_progress_help">#ffEE675C</color> <!-- red 400 --> <!-- Logout button --> <color name="logout_button_bg_color">#ccffffff</color> diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index 3f61d3c6af9a..fd37b3509a4e 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -126,6 +126,7 @@ public class AuthContainerView extends LinearLayout boolean mCredentialAllowed; boolean mSkipIntro; long mOperationId; + long mRequestId; @BiometricMultiSensorMode int mMultiSensorConfig; } @@ -172,6 +173,12 @@ public class AuthContainerView extends LinearLayout return this; } + /** Unique id for this request. */ + public Builder setRequestId(long requestId) { + mConfig.mRequestId = requestId; + return this; + } + /** The multi-sensor mode. */ public Builder setMultiSensorConfig(@BiometricMultiSensorMode int multiSensorConfig) { mConfig.mMultiSensorConfig = multiSensorConfig; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index ab5f2b8289be..bcc053068712 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -501,7 +501,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, @Override public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, - int userId, String opPackageName, long operationId, + int userId, long operationId, String opPackageName, long requestId, @BiometricMultiSensorMode int multiSensorConfig) { @Authenticators.Types final int authenticators = promptInfo.getAuthenticators(); @@ -515,6 +515,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, + ", credentialAllowed: " + credentialAllowed + ", requireConfirmation: " + requireConfirmation + ", operationId: " + operationId + + ", requestId: " + requestId + ", multiSensorConfig: " + multiSensorConfig); } SomeArgs args = SomeArgs.obtain(); @@ -526,6 +527,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, args.argi1 = userId; args.arg6 = opPackageName; args.arg7 = operationId; + args.arg8 = requestId; args.argi2 = multiSensorConfig; boolean skipAnimation = false; @@ -629,6 +631,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, if (mCurrentDialog == null) { // Could be possible if the caller canceled authentication after credential success // but before the client was notified. + if (DEBUG) Log.d(TAG, "dialog already gone"); return; } @@ -683,6 +686,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, final int userId = args.argi1; final String opPackageName = (String) args.arg6; final long operationId = (long) args.arg7; + final long requestId = (long) args.arg8; final @BiometricMultiSensorMode int multiSensorConfig = args.argi2; // Create a new dialog but do not replace the current one yet. @@ -695,6 +699,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, opPackageName, skipAnimation, operationId, + requestId, multiSensorConfig); if (newDialog == null) { @@ -772,7 +777,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, protected AuthDialog buildDialog(PromptInfo promptInfo, boolean requireConfirmation, int userId, int[] sensorIds, boolean credentialAllowed, String opPackageName, - boolean skipIntro, long operationId, + boolean skipIntro, long operationId, long requestId, @BiometricMultiSensorMode int multiSensorConfig) { return new AuthContainerView.Builder(mContext) .setCallback(this) @@ -782,6 +787,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, .setOpPackageName(opPackageName) .setSkipIntro(skipIntro) .setOperationId(operationId) + .setRequestId(requestId) .setMultiSensorConfig(multiSensorConfig) .build(sensorIds, credentialAllowed, mFpProps, mFaceProps); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java index ea69b1d626ae..b5273abd868d 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java @@ -143,6 +143,10 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable { mProgressDrawable.onLastStepAcquired(); } + void onEnrollmentHelp() { + mProgressDrawable.onEnrollmentHelp(); + } + @Override public void draw(@NonNull Canvas canvas) { mProgressDrawable.draw(canvas); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java index 6a918a6c8d39..19148e383005 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java @@ -50,6 +50,7 @@ public class UdfpsEnrollHelper { interface Listener { void onEnrollmentProgress(int remaining, int totalSteps); void onLastStepAcquired(); + void onEnrollmentHelp(); } @NonNull private final Context mContext; @@ -138,7 +139,9 @@ public class UdfpsEnrollHelper { } void onEnrollmentHelp() { - + if (mListener != null) { + mListener.onEnrollmentHelp(); + } } void setListener(Listener listener) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java index 4195009937c2..9c486b9ac1b4 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java @@ -16,7 +16,9 @@ package com.android.systemui.biometrics; +import android.animation.ArgbEvaluator; import android.animation.ValueAnimator; +import android.annotation.ColorInt; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; @@ -46,6 +48,11 @@ public class UdfpsEnrollProgressBarDrawable extends Drawable { @NonNull private final Paint mProgressPaint; @Nullable private ValueAnimator mProgressAnimator; + @Nullable private ValueAnimator mProgressShowingHelpAnimator; + @Nullable private ValueAnimator mProgressHidingHelpAnimator; + @ColorInt private final int mProgressColor; + @ColorInt private final int mProgressHelpColor; + private final int mShortAnimationDuration; private float mProgress; private int mRotation; // After last step, rotate the progress bar once private boolean mLastStepAcquired; @@ -55,6 +62,11 @@ public class UdfpsEnrollProgressBarDrawable extends Drawable { mContext = context; mParent = parent; + mShortAnimationDuration = context.getResources() + .getInteger(com.android.internal.R.integer.config_shortAnimTime); + mProgressColor = context.getColor(R.color.udfps_enroll_progress); + mProgressHelpColor = context.getColor(R.color.udfps_enroll_progress_help); + mBackgroundCirclePaint = new Paint(); mBackgroundCirclePaint.setStrokeWidth(Utils.dpToPixels(context, PROGRESS_BAR_THICKNESS_DP)); mBackgroundCirclePaint.setColor(context.getColor(R.color.white_disabled)); @@ -74,7 +86,7 @@ public class UdfpsEnrollProgressBarDrawable extends Drawable { // Progress should not be color extracted mProgressPaint = new Paint(); mProgressPaint.setStrokeWidth(Utils.dpToPixels(context, PROGRESS_BAR_THICKNESS_DP)); - mProgressPaint.setColor(context.getColor(R.color.udfps_enroll_progress)); + mProgressPaint.setColor(mProgressColor); mProgressPaint.setAntiAlias(true); mProgressPaint.setStyle(Paint.Style.STROKE); mProgressPaint.setStrokeCap(Paint.Cap.ROUND); @@ -92,7 +104,9 @@ public class UdfpsEnrollProgressBarDrawable extends Drawable { return; } - long animationDuration = 150; + long animationDuration = mShortAnimationDuration; + + hideEnrollmentHelp(); if (progress == 1.f) { animationDuration = 400; @@ -128,6 +142,47 @@ public class UdfpsEnrollProgressBarDrawable extends Drawable { mLastStepAcquired = true; } + void onEnrollmentHelp() { + if (mProgressShowingHelpAnimator != null || mProgressAnimator == null) { + return; // already showing or at 0% (no progress bar visible) + } + + if (mProgressHidingHelpAnimator != null && mProgressHidingHelpAnimator.isRunning()) { + mProgressHidingHelpAnimator.cancel(); + } + mProgressHidingHelpAnimator = null; + + mProgressShowingHelpAnimator = getProgressColorAnimator( + mProgressPaint.getColor(), mProgressHelpColor); + mProgressShowingHelpAnimator.start(); + } + + private void hideEnrollmentHelp() { + if (mProgressHidingHelpAnimator != null || mProgressShowingHelpAnimator == null) { + return; // already hidden or help never shown + } + + if (mProgressShowingHelpAnimator != null && mProgressShowingHelpAnimator.isRunning()) { + mProgressShowingHelpAnimator.cancel(); + } + mProgressShowingHelpAnimator = null; + + mProgressHidingHelpAnimator = getProgressColorAnimator( + mProgressPaint.getColor(), mProgressColor); + mProgressHidingHelpAnimator.start(); + } + + private ValueAnimator getProgressColorAnimator(@ColorInt int from, @ColorInt int to) { + final ValueAnimator animator = ValueAnimator.ofObject( + ArgbEvaluator.getInstance(), from, to); + animator.setDuration(mShortAnimationDuration); + animator.addUpdateListener(animation -> { + mProgressPaint.setColor((int) animation.getAnimatedValue()); + mParent.invalidateSelf(); + }); + return animator; + } + @Override public void draw(@NonNull Canvas canvas) { canvas.save(); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java index 2cdf49d6fc3c..56d5b317029f 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java @@ -64,4 +64,8 @@ public class UdfpsEnrollView extends UdfpsAnimationView { void onLastStepAcquired() { mHandler.post(mFingerprintDrawable::onLastStepAcquired); } + + void onEnrollmentHelp() { + mHandler.post(mFingerprintDrawable::onEnrollmentHelp); + } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java index 3dab010d917c..61534a5a83d1 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java @@ -42,6 +42,11 @@ public class UdfpsEnrollViewController extends UdfpsAnimationViewController<Udfp public void onLastStepAcquired() { mView.onLastStepAcquired(); } + + @Override + public void onEnrollmentHelp() { + mView.onEnrollmentHelp(); + } }; protected UdfpsEnrollViewController( diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java index 4d0cbd15a788..52bf2df53fb0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java @@ -486,8 +486,7 @@ public class InternetDialog extends SystemUIDialog implements } private void showTurnOffMobileDialog() { - CharSequence carrierName = - mSubscriptionManager.getDefaultDataSubscriptionInfo().getCarrierName(); + CharSequence carrierName = getMobileNetworkTitle(); boolean isInService = mInternetDialogController.isVoiceStateInService(); if (TextUtils.isEmpty(carrierName) || !isInService) { carrierName = mContext.getString(R.string.mobile_data_disable_message_default_carrier); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index 3fbdc23f55d0..8def475c192c 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -33,6 +33,7 @@ import static java.util.Objects.requireNonNull; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.annotation.MainThread; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityOptions; @@ -261,6 +262,7 @@ public class ScreenshotController { private Bitmap mScreenBitmap; private SaveImageInBackgroundTask mSaveInBgTask; private boolean mScreenshotTakenInPortrait; + private boolean mBlockAttach; private Animator mScreenshotAnimation; private RequestCallback mCurrentRequestCallback; @@ -731,6 +733,7 @@ public class ScreenshotController { new ViewTreeObserver.OnWindowAttachListener() { @Override public void onWindowAttached() { + mBlockAttach = false; decorView.getViewTreeObserver().removeOnWindowAttachListener(this); action.run(); } @@ -747,14 +750,16 @@ public class ScreenshotController { mWindow.setContentView(contentView); } + @MainThread private void attachWindow() { View decorView = mWindow.getDecorView(); - if (decorView.isAttachedToWindow()) { + if (decorView.isAttachedToWindow() || mBlockAttach) { return; } if (DEBUG_WINDOW) { Log.d(TAG, "attachWindow"); } + mBlockAttach = true; mWindowManager.addView(decorView, mWindowLayoutParams); decorView.requestApplyInsets(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 8e52b0da54ef..50911d162113 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -290,8 +290,8 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< default void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, int[] sensorIds, boolean credentialAllowed, - boolean requireConfirmation, int userId, String opPackageName, - long operationId, @BiometricMultiSensorMode int multiSensorConfig) { + boolean requireConfirmation, int userId, long operationId, String opPackageName, + long requestId, @BiometricMultiSensorMode int multiSensorConfig) { } /** @see IStatusBar#onBiometricAuthenticated() */ @@ -843,7 +843,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< @Override public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, - int userId, String opPackageName, long operationId, + int userId, long operationId, String opPackageName, long requestId, @BiometricMultiSensorMode int multiSensorConfig) { synchronized (mLock) { SomeArgs args = SomeArgs.obtain(); @@ -855,6 +855,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< args.argi1 = userId; args.arg6 = opPackageName; args.arg7 = operationId; + args.arg8 = requestId; args.argi2 = multiSensorConfig; mHandler.obtainMessage(MSG_BIOMETRIC_SHOW, args) .sendToTarget(); @@ -1312,8 +1313,9 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< (boolean) someArgs.arg4 /* credentialAllowed */, (boolean) someArgs.arg5 /* requireConfirmation */, someArgs.argi1 /* userId */, - (String) someArgs.arg6 /* opPackageName */, (long) someArgs.arg7 /* operationId */, + (String) someArgs.arg6 /* opPackageName */, + (long) someArgs.arg8 /* requestId */, someArgs.argi2 /* multiSensorConfig */); } someArgs.recycle(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index 39d5314107ee..8dd5d6c01394 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -565,8 +565,9 @@ public class AuthControllerTest extends SysuiTestCase { credentialAllowed, true /* requireConfirmation */, 0 /* userId */, - "testPackage", 0 /* operationId */, + "testPackage", + 1 /* requestId */, BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT); } @@ -612,7 +613,7 @@ public class AuthControllerTest extends SysuiTestCase { @Override protected AuthDialog buildDialog(PromptInfo promptInfo, boolean requireConfirmation, int userId, int[] sensorIds, boolean credentialAllowed, - String opPackageName, boolean skipIntro, long operationId, + String opPackageName, boolean skipIntro, long operationId, long requestId, @BiometricManager.BiometricMultiSensorMode int multiSensorConfig) { mLastBiometricPromptInfo = promptInfo; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java index 21c6292c151f..f3762c566731 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java @@ -423,17 +423,18 @@ public class CommandQueueTest extends SysuiTestCase { final boolean credentialAllowed = true; final boolean requireConfirmation = true; final int userId = 10; - final String packageName = "test"; final long operationId = 1; + final String packageName = "test"; + final long requestId = 10; final int multiSensorConfig = BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT; mCommandQueue.showAuthenticationDialog(promptInfo, receiver, sensorIds, - credentialAllowed, requireConfirmation , userId, packageName, operationId, + credentialAllowed, requireConfirmation, userId, operationId, packageName, requestId, multiSensorConfig); waitForIdleSync(); verify(mCallbacks).showAuthenticationDialog(eq(promptInfo), eq(receiver), eq(sensorIds), - eq(credentialAllowed), eq(requireConfirmation), eq(userId), eq(packageName), - eq(operationId), eq(multiSensorConfig)); + eq(credentialAllowed), eq(requireConfirmation), eq(userId), eq(operationId), + eq(packageName), eq(requestId), eq(multiSensorConfig)); } @Test diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 3c0fe717a722..5e67c5438550 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -2823,8 +2823,8 @@ public class AudioService extends IAudioService.Stub if (uid == android.os.Process.SYSTEM_UID) { uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid)); } - if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage) - != AppOpsManager.MODE_ALLOWED) { + // validate calling package and app op + if (!checkNoteAppOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)) { return; } @@ -3547,8 +3547,7 @@ public class AudioService extends IAudioService.Stub if (uid == android.os.Process.SYSTEM_UID) { uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid)); } - if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage) - != AppOpsManager.MODE_ALLOWED) { + if (!checkNoteAppOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)) { return; } @@ -3983,8 +3982,7 @@ public class AudioService extends IAudioService.Stub uid = UserHandle.getUid(userId, UserHandle.getAppId(uid)); } // If OP_AUDIO_MASTER_VOLUME is set, disallow unmuting. - if (!mute && mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage) - != AppOpsManager.MODE_ALLOWED) { + if (!mute && !checkNoteAppOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)) { return; } if (userId != UserHandle.getCallingUserId() && @@ -4115,8 +4113,7 @@ public class AudioService extends IAudioService.Stub ? MediaMetrics.Value.MUTE : MediaMetrics.Value.UNMUTE); // If OP_MUTE_MICROPHONE is set, disallow unmuting. - if (!on && mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, uid, callingPackage) - != AppOpsManager.MODE_ALLOWED) { + if (!on && !checkNoteAppOp(AppOpsManager.OP_MUTE_MICROPHONE, uid, callingPackage)) { mmi.set(MediaMetrics.Property.EARLY_RETURN, "disallow unmuting").record(); return; } @@ -10534,4 +10531,31 @@ public class AudioService extends IAudioService.Stub } mFullVolumeDevices.remove(audioSystemDeviceOut); } + + //==================== + // Helper functions for app ops + //==================== + /** + * Validates, and notes an app op for a given uid and package name. + * Validation comes from exception catching: a security exception indicates the package + * doesn't exist, an IAE indicates the uid and package don't match. The code only checks + * if exception was thrown for robustness to code changes in op validation + * @param op the app op to check + * @param uid the uid of the caller + * @param packageName the package to check + * @return true if the origin of the call is valid (no uid / package mismatch) and the caller + * is allowed to perform the operation + */ + private boolean checkNoteAppOp(int op, int uid, String packageName) { + try { + if (mAppOps.noteOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) { + return false; + } + } catch (Exception e) { + Log.e(TAG, "Error noting op:" + op + " on uid:" + uid + " for package:" + + packageName, e); + return false; + } + return true; + } } diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java index 0cd2e3d0ff59..b42f8980d1c0 100644 --- a/services/core/java/com/android/server/biometrics/AuthService.java +++ b/services/core/java/com/android/server/biometrics/AuthService.java @@ -206,7 +206,7 @@ public class AuthService extends SystemService { } @Override - public void authenticate(IBinder token, long sessionId, int userId, + public long authenticate(IBinder token, long sessionId, int userId, IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) throws RemoteException { // Only allow internal clients to authenticate with a different userId. @@ -223,18 +223,18 @@ public class AuthService extends SystemService { if (!checkAppOps(callingUid, opPackageName, "authenticate()")) { authenticateFastFail("Denied by app ops: " + opPackageName, receiver); - return; + return -1; } if (token == null || receiver == null || opPackageName == null || promptInfo == null) { authenticateFastFail( "Unable to authenticate, one or more null arguments", receiver); - return; + return -1; } if (!Utils.isForeground(callingUid, callingPid)) { authenticateFastFail("Caller is not foreground: " + opPackageName, receiver); - return; + return -1; } if (promptInfo.containsTestConfigurations()) { @@ -251,7 +251,7 @@ public class AuthService extends SystemService { final long identity = Binder.clearCallingIdentity(); try { - mBiometricService.authenticate( + return mBiometricService.authenticate( token, sessionId, userId, receiver, opPackageName, promptInfo); } finally { Binder.restoreCallingIdentity(identity); @@ -270,7 +270,7 @@ public class AuthService extends SystemService { } @Override - public void cancelAuthentication(IBinder token, String opPackageName) + public void cancelAuthentication(IBinder token, String opPackageName, long requestId) throws RemoteException { checkPermission(); @@ -281,7 +281,7 @@ public class AuthService extends SystemService { final long identity = Binder.clearCallingIdentity(); try { - mBiometricService.cancelAuthentication(token, opPackageName); + mBiometricService.cancelAuthentication(token, opPackageName, requestId); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java index bdde980f5cae..0da6a1ba3109 100644 --- a/services/core/java/com/android/server/biometrics/AuthSession.java +++ b/services/core/java/com/android/server/biometrics/AuthSession.java @@ -128,6 +128,7 @@ public final class AuthSession implements IBinder.DeathRecipient { @VisibleForTesting final IBinder mToken; // Info to be shown on BiometricDialog when all cookies are returned. @VisibleForTesting final PromptInfo mPromptInfo; + private final long mRequestId; private final long mOperationId; private final int mUserId; private final IBiometricSensorReceiver mSensorReceiver; @@ -142,6 +143,8 @@ public final class AuthSession implements IBinder.DeathRecipient { private @BiometricMultiSensorMode int mMultiSensorMode; private @MultiSensorState int mMultiSensorState; private int[] mSensors; + // TODO(b/197265902): merge into state + private boolean mCancelled; // For explicit confirmation, do not send to keystore until the user has confirmed // the authentication. private byte[] mTokenEscrow; @@ -162,6 +165,7 @@ public final class AuthSession implements IBinder.DeathRecipient { @NonNull ClientDeathReceiver clientDeathReceiver, @NonNull PreAuthInfo preAuthInfo, @NonNull IBinder token, + long requestId, long operationId, int userId, @NonNull IBiometricSensorReceiver sensorReceiver, @@ -179,6 +183,7 @@ public final class AuthSession implements IBinder.DeathRecipient { mClientDeathReceiver = clientDeathReceiver; mPreAuthInfo = preAuthInfo; mToken = token; + mRequestId = requestId; mOperationId = operationId; mUserId = userId; mSensorReceiver = sensorReceiver; @@ -187,6 +192,7 @@ public final class AuthSession implements IBinder.DeathRecipient { mPromptInfo = promptInfo; mDebugEnabled = debugEnabled; mFingerprintSensorProperties = fingerprintSensorProperties; + mCancelled = false; try { mClientReceiver.asBinder().linkToDeath(this, 0 /* flags */); @@ -233,7 +239,7 @@ public final class AuthSession implements IBinder.DeathRecipient { Slog.v(TAG, "waiting for cooking for sensor: " + sensor.id); } sensor.goToStateWaitingForCookie(requireConfirmation, mToken, mOperationId, - mUserId, mSensorReceiver, mOpPackageName, cookie, + mUserId, mSensorReceiver, mOpPackageName, mRequestId, cookie, mPromptInfo.isAllowBackgroundAuthentication()); } } @@ -255,8 +261,9 @@ public final class AuthSession implements IBinder.DeathRecipient { true /* credentialAllowed */, false /* requireConfirmation */, mUserId, - mOpPackageName, mOperationId, + mOpPackageName, + mRequestId, mMultiSensorMode); } else if (!mPreAuthInfo.eligibleSensors.isEmpty()) { // Some combination of biometric or biometric|credential is requested @@ -270,6 +277,11 @@ public final class AuthSession implements IBinder.DeathRecipient { } void onCookieReceived(int cookie) { + if (mCancelled) { + Slog.w(TAG, "Received cookie but already cancelled (ignoring): " + cookie); + return; + } + for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) { sensor.goToStateCookieReturnedIfCookieMatches(cookie); } @@ -301,8 +313,9 @@ public final class AuthSession implements IBinder.DeathRecipient { mPreAuthInfo.shouldShowCredential(), requireConfirmation, mUserId, - mOpPackageName, mOperationId, + mOpPackageName, + mRequestId, mMultiSensorMode); mState = STATE_AUTH_STARTED; } catch (RemoteException e) { @@ -369,7 +382,7 @@ public final class AuthSession implements IBinder.DeathRecipient { final boolean shouldCancel = filter.apply(sensor); Slog.d(TAG, "sensorId: " + sensor.id + ", shouldCancel: " + shouldCancel); if (shouldCancel) { - sensor.goToStateCancelling(mToken, mOpPackageName); + sensor.goToStateCancelling(mToken, mOpPackageName, mRequestId); } } catch (RemoteException e) { Slog.e(TAG, "Unable to cancel authentication"); @@ -425,8 +438,9 @@ public final class AuthSession implements IBinder.DeathRecipient { true /* credentialAllowed */, false /* requireConfirmation */, mUserId, - mOpPackageName, mOperationId, + mOpPackageName, + mRequestId, mMultiSensorMode); } else { mClientReceiver.onError(modality, error, vendorCode); @@ -775,6 +789,8 @@ public final class AuthSession implements IBinder.DeathRecipient { * @return true if this AuthSession is finished, e.g. should be set to null */ boolean onCancelAuthSession(boolean force) { + mCancelled = true; + final boolean authStarted = mState == STATE_AUTH_CALLED || mState == STATE_AUTH_STARTED || mState == STATE_AUTH_STARTED_UI_SHOWING; @@ -820,6 +836,7 @@ public final class AuthSession implements IBinder.DeathRecipient { return Utils.isCredentialRequested(mPromptInfo); } + @VisibleForTesting boolean allCookiesReceived() { final int remainingCookies = mPreAuthInfo.numSensorsWaitingForCookie(); Slog.d(TAG, "Remaining cookies: " + remainingCookies); @@ -839,6 +856,10 @@ public final class AuthSession implements IBinder.DeathRecipient { return mState; } + long getRequestId() { + return mRequestId; + } + private int statsModality() { int modality = 0; @@ -901,7 +922,9 @@ public final class AuthSession implements IBinder.DeathRecipient { @Override public String toString() { return "State: " + mState + + ", cancelled: " + mCancelled + ", isCrypto: " + isCrypto() - + ", PreAuthInfo: " + mPreAuthInfo; + + ", PreAuthInfo: " + mPreAuthInfo + + ", requestId: " + mRequestId; } } diff --git a/services/core/java/com/android/server/biometrics/BiometricSensor.java b/services/core/java/com/android/server/biometrics/BiometricSensor.java index 8a842b53d8e8..0333c3e247c0 100644 --- a/services/core/java/com/android/server/biometrics/BiometricSensor.java +++ b/services/core/java/com/android/server/biometrics/BiometricSensor.java @@ -108,11 +108,11 @@ public abstract class BiometricSensor { void goToStateWaitingForCookie(boolean requireConfirmation, IBinder token, long sessionId, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, - int cookie, boolean allowBackgroundAuthentication) + long requestId, int cookie, boolean allowBackgroundAuthentication) throws RemoteException { mCookie = cookie; impl.prepareForAuthentication(requireConfirmation, token, - sessionId, userId, sensorReceiver, opPackageName, mCookie, + sessionId, userId, sensorReceiver, opPackageName, requestId, mCookie, allowBackgroundAuthentication); mSensorState = STATE_WAITING_FOR_COOKIE; } @@ -129,8 +129,9 @@ public abstract class BiometricSensor { mSensorState = STATE_AUTHENTICATING; } - void goToStateCancelling(IBinder token, String opPackageName) throws RemoteException { - impl.cancelAuthenticationFromService(token, opPackageName); + void goToStateCancelling(IBinder token, String opPackageName, long requestId) + throws RemoteException { + impl.cancelAuthenticationFromService(token, opPackageName, requestId); mSensorState = STATE_CANCELING; } diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index b1d300cd838e..e0775d48b42f 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -83,6 +83,7 @@ import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; /** * System service that arbitrates the modality for BiometricPrompt to use. @@ -115,6 +116,7 @@ public class BiometricService extends SystemService { final SettingObserver mSettingObserver; private final List<EnabledOnKeyguardCallback> mEnabledOnKeyguardCallbacks; private final Random mRandom = new Random(); + @NonNull private final AtomicLong mRequestCounter; @VisibleForTesting IStatusBarService mStatusBarService; @@ -194,6 +196,7 @@ public class BiometricService extends SystemService { SomeArgs args = (SomeArgs) msg.obj; handleAuthenticate( (IBinder) args.arg1 /* token */, + (long) args.arg6 /* requestId */, (long) args.arg2 /* operationId */, args.argi1 /* userid */, (IBiometricServiceReceiver) args.arg3 /* receiver */, @@ -204,7 +207,9 @@ public class BiometricService extends SystemService { } case MSG_CANCEL_AUTHENTICATION: { - handleCancelAuthentication(); + SomeArgs args = (SomeArgs) msg.obj; + handleCancelAuthentication((long) args.arg3 /* requestId */); + args.recycle(); break; } @@ -683,13 +688,13 @@ public class BiometricService extends SystemService { } @Override // Binder call - public void authenticate(IBinder token, long operationId, int userId, + public long authenticate(IBinder token, long operationId, int userId, IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) { checkInternalPermission(); if (token == null || receiver == null || opPackageName == null || promptInfo == null) { Slog.e(TAG, "Unable to authenticate, one or more null arguments"); - return; + return -1; } if (!Utils.isValidAuthenticatorConfig(promptInfo)) { @@ -706,6 +711,8 @@ public class BiometricService extends SystemService { } } + final long requestId = mRequestCounter.incrementAndGet(); + SomeArgs args = SomeArgs.obtain(); args.arg1 = token; args.arg2 = operationId; @@ -713,15 +720,23 @@ public class BiometricService extends SystemService { args.arg3 = receiver; args.arg4 = opPackageName; args.arg5 = promptInfo; + args.arg6 = requestId; mHandler.obtainMessage(MSG_AUTHENTICATE, args).sendToTarget(); + + return requestId; } @Override // Binder call - public void cancelAuthentication(IBinder token, String opPackageName) { + public void cancelAuthentication(IBinder token, String opPackageName, long requestId) { checkInternalPermission(); - mHandler.obtainMessage(MSG_CANCEL_AUTHENTICATION).sendToTarget(); + SomeArgs args = SomeArgs.obtain(); + args.arg1 = token; + args.arg2 = opPackageName; + args.arg3 = requestId; + + mHandler.obtainMessage(MSG_CANCEL_AUTHENTICATION, args).sendToTarget(); } @Override // Binder call @@ -1111,6 +1126,10 @@ public class BiometricService extends SystemService { return Settings.Secure.getInt(context.getContentResolver(), CoexCoordinator.FACE_HAPTIC_DISABLE, 1) != 0; } + + public AtomicLong getRequestGenerator() { + return new AtomicLong(0); + } } /** @@ -1136,6 +1155,7 @@ public class BiometricService extends SystemService { mEnabledOnKeyguardCallbacks = new ArrayList<>(); mSettingObserver = mInjector.getSettingObserver(context, mHandler, mEnabledOnKeyguardCallbacks); + mRequestCounter = mInjector.getRequestGenerator(); // TODO(b/193089985) This logic lives here (outside of CoexCoordinator) so that it doesn't // need to depend on context. We can remove this code once the advanced logic is enabled @@ -1349,7 +1369,7 @@ public class BiometricService extends SystemService { mCurrentAuthSession.onCookieReceived(cookie); } - private void handleAuthenticate(IBinder token, long operationId, int userId, + private void handleAuthenticate(IBinder token, long requestId, long operationId, int userId, IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) { mHandler.post(() -> { try { @@ -1360,7 +1380,8 @@ public class BiometricService extends SystemService { final Pair<Integer, Integer> preAuthStatus = preAuthInfo.getPreAuthenticateStatus(); Slog.d(TAG, "handleAuthenticate: modality(" + preAuthStatus.first - + "), status(" + preAuthStatus.second + "), preAuthInfo: " + preAuthInfo); + + "), status(" + preAuthStatus.second + "), preAuthInfo: " + preAuthInfo + + " requestId: " + requestId); if (preAuthStatus.second == BiometricConstants.BIOMETRIC_SUCCESS) { // If BIOMETRIC_WEAK or BIOMETRIC_STRONG are allowed, but not enrolled, but @@ -1372,8 +1393,8 @@ public class BiometricService extends SystemService { promptInfo.setAuthenticators(Authenticators.DEVICE_CREDENTIAL); } - authenticateInternal(token, operationId, userId, receiver, opPackageName, - promptInfo, preAuthInfo); + authenticateInternal(token, requestId, operationId, userId, receiver, + opPackageName, promptInfo, preAuthInfo); } else { receiver.onError(preAuthStatus.first /* modality */, preAuthStatus.second /* errorCode */, @@ -1394,7 +1415,7 @@ public class BiometricService extends SystemService { * Note that this path is NOT invoked when the BiometricPrompt "Try again" button is pressed. * In that case, see {@link #handleOnTryAgainPressed()}. */ - private void authenticateInternal(IBinder token, long operationId, int userId, + private void authenticateInternal(IBinder token, long requestId, long operationId, int userId, IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo, PreAuthInfo preAuthInfo) { Slog.d(TAG, "Creating authSession with authRequest: " + preAuthInfo); @@ -1412,9 +1433,9 @@ public class BiometricService extends SystemService { final boolean debugEnabled = mInjector.isDebugEnabled(getContext(), userId); mCurrentAuthSession = new AuthSession(getContext(), mStatusBarService, mSysuiReceiver, - mKeyStore, mRandom, mClientDeathReceiver, preAuthInfo, token, operationId, userId, - mBiometricSensorReceiver, receiver, opPackageName, promptInfo, debugEnabled, - mInjector.getFingerprintSensorProperties(getContext())); + mKeyStore, mRandom, mClientDeathReceiver, preAuthInfo, token, requestId, + operationId, userId, mBiometricSensorReceiver, receiver, opPackageName, promptInfo, + debugEnabled, mInjector.getFingerprintSensorProperties(getContext())); try { mCurrentAuthSession.goToInitialState(); } catch (RemoteException e) { @@ -1422,11 +1443,21 @@ public class BiometricService extends SystemService { } } - private void handleCancelAuthentication() { + private void handleCancelAuthentication(long requestId) { if (mCurrentAuthSession == null) { Slog.e(TAG, "handleCancelAuthentication: AuthSession is null"); return; } + if (mCurrentAuthSession.getRequestId() != requestId) { + // TODO: actually cancel the operation + // This can happen if the operation has been queued, but is cancelled before + // it reaches the head of the scheduler. Consider it a programming error for now + // and ignore it. + Slog.e(TAG, "handleCancelAuthentication: AuthSession mismatch current requestId: " + + mCurrentAuthSession.getRequestId() + " cancel for: " + requestId + + " (ignoring cancellation)"); + return; + } final boolean finished = mCurrentAuthSession.onCancelAuthSession(false /* force */); if (finished) { diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java index 3eb6f4ae48a2..0a1c77bf10a2 100644 --- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java +++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java @@ -101,6 +101,7 @@ public abstract class BaseClientMonitor extends LoggableMonitor private final int mSensorId; // sensorId as configured by the framework @Nullable private IBinder mToken; + private long mRequestId; @Nullable private ClientMonitorCallbackConverter mListener; // Currently only used for authentication client. The cookie generated by BiometricService // is never 0. @@ -154,6 +155,7 @@ public abstract class BaseClientMonitor extends LoggableMonitor mSequentialId = sCount++; mContext = context; mToken = token; + mRequestId = -1; mListener = listener; mTargetUserId = userId; mOwner = owner; @@ -258,6 +260,29 @@ public abstract class BaseClientMonitor extends LoggableMonitor return mSensorId; } + /** Unique request id. */ + public final long getRequestId() { + return mRequestId; + } + + /** If a unique id has been set via {@link #setRequestId(long)} */ + public final boolean hasRequestId() { + return mRequestId > 0; + } + + /** + * A unique identifier used to tie this operation to a request (i.e an API invocation). + * + * Subclasses should not call this method if this operation does not have a direct + * correspondence to a request and {@link #hasRequestId()} will return false. + */ + protected final void setRequestId(long id) { + if (id <= 0) { + throw new IllegalArgumentException("request id must be positive"); + } + mRequestId = id; + } + @VisibleForTesting public Callback getCallback() { return mCallback; @@ -270,6 +295,7 @@ public abstract class BaseClientMonitor extends LoggableMonitor + ", proto=" + getProtoEnum() + ", owner=" + getOwnerString() + ", cookie=" + getCookie() + + ", requestId=" + getRequestId() + ", userId=" + getTargetUserId() + "}"; } } diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java index feb9e2a5b03f..361ec40f2877 100644 --- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java +++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java @@ -643,22 +643,18 @@ public class BiometricScheduler { /** * Requests to cancel authentication or detection. * @param token from the caller, should match the token passed in when requesting authentication + * @param requestId the id returned when requesting authentication */ - public void cancelAuthenticationOrDetection(IBinder token) { - if (mCurrentOperation == null) { - Slog.e(getTag(), "Unable to cancel authentication, null operation"); - return; - } - final boolean isCorrectClient = isAuthenticationOrDetectionOperation(mCurrentOperation); - final boolean tokenMatches = mCurrentOperation.mClientMonitor.getToken() == token; - - Slog.d(getTag(), "cancelAuthenticationOrDetection, isCorrectClient: " + isCorrectClient - + ", tokenMatches: " + tokenMatches); + public void cancelAuthenticationOrDetection(IBinder token, long requestId) { + Slog.d(getTag(), "cancelAuthenticationOrDetection, requestId: " + requestId + + " current: " + mCurrentOperation + + " stack size: " + mPendingOperations.size()); - if (isCorrectClient && tokenMatches) { + if (mCurrentOperation != null + && canCancelAuthOperation(mCurrentOperation, token, requestId)) { Slog.d(getTag(), "Cancelling: " + mCurrentOperation); cancelInternal(mCurrentOperation); - } else if (!isCorrectClient) { + } else { // Look through the current queue for all authentication clients for the specified // token, and mark them as STATE_WAITING_IN_QUEUE_CANCELING. Note that we're marking // all of them, instead of just the first one, since the API surface currently doesn't @@ -666,8 +662,7 @@ public class BiometricScheduler { // process. However, this generally does not happen anyway, and would be a class of // bugs on its own. for (Operation operation : mPendingOperations) { - if (isAuthenticationOrDetectionOperation(operation) - && operation.mClientMonitor.getToken() == token) { + if (canCancelAuthOperation(operation, token, requestId)) { Slog.d(getTag(), "Marking " + operation + " as STATE_WAITING_IN_QUEUE_CANCELING"); operation.mState = Operation.STATE_WAITING_IN_QUEUE_CANCELING; @@ -676,10 +671,26 @@ public class BiometricScheduler { } } - private boolean isAuthenticationOrDetectionOperation(@NonNull Operation operation) { - final boolean isAuthentication = operation.mClientMonitor - instanceof AuthenticationConsumer; - final boolean isDetection = operation.mClientMonitor instanceof DetectionConsumer; + private static boolean canCancelAuthOperation(Operation operation, IBinder token, + long requestId) { + // TODO: restrict callers that can cancel without requestId (negative value)? + return isAuthenticationOrDetectionOperation(operation) + && operation.mClientMonitor.getToken() == token + && isMatchingRequestId(operation, requestId); + } + + // By default, monitors are not associated with a request id to retain the original + // behavior (i.e. if no requestId is explicitly set then assume it matches) + private static boolean isMatchingRequestId(Operation operation, long requestId) { + return !operation.mClientMonitor.hasRequestId() + || operation.mClientMonitor.getRequestId() == requestId; + } + + private static boolean isAuthenticationOrDetectionOperation(@NonNull Operation operation) { + final boolean isAuthentication = + operation.mClientMonitor instanceof AuthenticationConsumer; + final boolean isDetection = + operation.mClientMonitor instanceof DetectionConsumer; return isAuthentication || isDetection; } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java index 0bc4f1b54d59..b2fd46d1475d 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java @@ -61,10 +61,11 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub { @Override public void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, - String opPackageName, int cookie, boolean allowBackgroundAuthentication) + String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication) throws RemoteException { mFaceService.prepareForAuthentication(mSensorId, requireConfirmation, token, operationId, - userId, sensorReceiver, opPackageName, cookie, allowBackgroundAuthentication); + userId, sensorReceiver, opPackageName, requestId, cookie, + allowBackgroundAuthentication); } @Override @@ -73,9 +74,9 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub { } @Override - public void cancelAuthenticationFromService(IBinder token, String opPackageName) + public void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId) throws RemoteException { - mFaceService.cancelAuthenticationFromService(mSensorId, token, opPackageName); + mFaceService.cancelAuthenticationFromService(mSensorId, token, opPackageName, requestId); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java index 12d6b08b8bcf..675ee545a14f 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java @@ -250,7 +250,7 @@ public class FaceService extends SystemService { } @Override // Binder call - public void authenticate(final IBinder token, final long operationId, int userId, + public long authenticate(final IBinder token, final long operationId, int userId, final IFaceServiceReceiver receiver, final String opPackageName, boolean isKeyguardBypassEnabled) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); @@ -270,38 +270,38 @@ public class FaceService extends SystemService { final Pair<Integer, ServiceProvider> provider = getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for authenticate"); - return; + return -1; } - provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, + return provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, 0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName, restricted, statsClient, isKeyguard, isKeyguardBypassEnabled); } @Override // Binder call - public void detectFace(final IBinder token, final int userId, + public long detectFace(final IBinder token, final int userId, final IFaceServiceReceiver receiver, final String opPackageName) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); if (!Utils.isKeyguard(getContext(), opPackageName)) { Slog.w(TAG, "detectFace called from non-sysui package: " + opPackageName); - return; + return -1; } if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) { // If this happens, something in KeyguardUpdateMonitor is wrong. This should only // ever be invoked when the user is encrypted or lockdown. Slog.e(TAG, "detectFace invoked when user is not encrypted or lockdown"); - return; + return -1; } final Pair<Integer, ServiceProvider> provider = getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for detectFace"); - return; + return -1; } - provider.second.scheduleFaceDetect(provider.first, token, userId, + return provider.second.scheduleFaceDetect(provider.first, token, userId, new ClientMonitorCallbackConverter(receiver), opPackageName, BiometricsProtoEnums.CLIENT_KEYGUARD); } @@ -309,8 +309,8 @@ public class FaceService extends SystemService { @Override // Binder call public void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, long operationId, int userId, - IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie, - boolean allowBackgroundAuthentication) { + IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId, + int cookie, boolean allowBackgroundAuthentication) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); final ServiceProvider provider = getProviderForSensor(sensorId); @@ -322,9 +322,9 @@ public class FaceService extends SystemService { final boolean isKeyguardBypassEnabled = false; // only valid for keyguard clients final boolean restricted = true; // BiometricPrompt is always restricted provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie, - new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted, - BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication, - isKeyguardBypassEnabled); + new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, requestId, + restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, + allowBackgroundAuthentication, isKeyguardBypassEnabled); } @Override // Binder call @@ -341,7 +341,8 @@ public class FaceService extends SystemService { } @Override // Binder call - public void cancelAuthentication(final IBinder token, final String opPackageName) { + public void cancelAuthentication(final IBinder token, final String opPackageName, + final long requestId) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); final Pair<Integer, ServiceProvider> provider = getSingleProvider(); @@ -350,11 +351,12 @@ public class FaceService extends SystemService { return; } - provider.second.cancelAuthentication(provider.first, token); + provider.second.cancelAuthentication(provider.first, token, requestId); } @Override // Binder call - public void cancelFaceDetect(final IBinder token, final String opPackageName) { + public void cancelFaceDetect(final IBinder token, final String opPackageName, + final long requestId) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); if (!Utils.isKeyguard(getContext(), opPackageName)) { Slog.w(TAG, "cancelFaceDetect called from non-sysui package: " @@ -368,12 +370,12 @@ public class FaceService extends SystemService { return; } - provider.second.cancelFaceDetect(provider.first, token); + provider.second.cancelFaceDetect(provider.first, token, requestId); } @Override // Binder call public void cancelAuthenticationFromService(int sensorId, final IBinder token, - final String opPackageName) { + final String opPackageName, final long requestId) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); final ServiceProvider provider = getProviderForSensor(sensorId); @@ -382,7 +384,7 @@ public class FaceService extends SystemService { return; } - provider.cancelAuthentication(sensorId, token); + provider.cancelAuthentication(sensorId, token, requestId); } @Override // Binder call diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java index 93ab1b65edff..e099ba372b05 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java @@ -101,18 +101,23 @@ public interface ServiceProvider { void cancelEnrollment(int sensorId, @NonNull IBinder token); - void scheduleFaceDetect(int sensorId, @NonNull IBinder token, int userId, + long scheduleFaceDetect(int sensorId, @NonNull IBinder token, int userId, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, int statsClient); - void cancelFaceDetect(int sensorId, @NonNull IBinder token); + void cancelFaceDetect(int sensorId, @NonNull IBinder token, long requestId); - void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, + long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, boolean restricted, int statsClient, boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled); - void cancelAuthentication(int sensorId, @NonNull IBinder token); + void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, + int cookie, @NonNull ClientMonitorCallbackConverter callback, + @NonNull String opPackageName, long requestId, boolean restricted, int statsClient, + boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled); + + void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId); void scheduleRemove(int sensorId, @NonNull IBinder token, int faceId, int userId, @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java index d66a27920f49..cbceba6cc959 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java @@ -65,7 +65,8 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements @FaceManager.FaceAcquired private int mLastAcquire = FaceManager.FACE_ACQUIRED_UNKNOWN; FaceAuthenticationClient(@NonNull Context context, - @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token, + @NonNull LazyDaemon<ISession> lazyDaemon, + @NonNull IBinder token, long requestId, @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId, boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric, int statsClient, @NonNull UsageStats usageStats, @@ -76,6 +77,7 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */, lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */, isKeyguardBypassEnabled); + setRequestId(requestId); mUsageStats = usageStats; mLockoutCache = lockoutCache; mNotificationManager = context.getSystemService(NotificationManager.class); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java index 1e73ac528f08..2ef0911658b1 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java @@ -43,11 +43,13 @@ public class FaceDetectClient extends AcquisitionClient<ISession> implements Det @Nullable private ICancellationSignal mCancellationSignal; public FaceDetectClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon, - @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, + @NonNull IBinder token, long requestId, + @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner, int sensorId, boolean isStrongBiometric, int statsClient) { super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FACE, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient); + setRequestId(requestId); mIsStrongBiometric = isStrongBiometric; } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java index 718b9da968f5..4bae7756abe0 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java @@ -65,6 +65,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicLong; /** * Provider for a single instance of the {@link IFace} HAL. @@ -83,6 +84,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { @NonNull private final UsageStats mUsageStats; @NonNull private final ActivityTaskManager mActivityTaskManager; @NonNull private final BiometricTaskStackListener mTaskStackListener; + // for requests that do not use biometric prompt + @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0); @Nullable private IFace mDaemon; @@ -110,8 +113,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { && !client.isAlreadyDone()) { Slog.e(getTag(), "Stopping background authentication, top: " + topPackage + " currentClient: " + client); - mSensors.valueAt(i).getScheduler() - .cancelAuthenticationOrDetection(client.getToken()); + mSensors.valueAt(i).getScheduler().cancelAuthenticationOrDetection( + client.getToken(), client.getRequestId()); } } } @@ -356,34 +359,39 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { } @Override - public void scheduleFaceDetect(int sensorId, @NonNull IBinder token, + public long scheduleFaceDetect(int sensorId, @NonNull IBinder token, int userId, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, int statsClient) { + final long id = mRequestCounter.incrementAndGet(); + mHandler.post(() -> { final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId); final FaceDetectClient client = new FaceDetectClient(mContext, - mSensors.get(sensorId).getLazySession(), token, callback, userId, opPackageName, + mSensors.get(sensorId).getLazySession(), + token, id, callback, userId, opPackageName, sensorId, isStrongBiometric, statsClient); scheduleForSensor(sensorId, client); }); + + return id; } @Override - public void cancelFaceDetect(int sensorId, @NonNull IBinder token) { + public void cancelFaceDetect(int sensorId, @NonNull IBinder token, long requestId) { mHandler.post(() -> mSensors.get(sensorId).getScheduler() - .cancelAuthenticationOrDetection(token)); + .cancelAuthenticationOrDetection(token, requestId)); } @Override public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback, - @NonNull String opPackageName, boolean restricted, int statsClient, + @NonNull String opPackageName, long requestId, boolean restricted, int statsClient, boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) { mHandler.post(() -> { final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId); final FaceAuthenticationClient client = new FaceAuthenticationClient( - mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId, - operationId, restricted, opPackageName, cookie, + mContext, mSensors.get(sensorId).getLazySession(), token, requestId, callback, + userId, operationId, restricted, opPackageName, cookie, false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient, mUsageStats, mSensors.get(sensorId).getLockoutCache(), allowBackgroundAuthentication, isKeyguardBypassEnabled); @@ -392,9 +400,23 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { } @Override - public void cancelAuthentication(int sensorId, @NonNull IBinder token) { + public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, + int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback, + @NonNull String opPackageName, boolean restricted, int statsClient, + boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) { + final long id = mRequestCounter.incrementAndGet(); + + scheduleAuthenticate(sensorId, token, operationId, userId, cookie, callback, + opPackageName, id, restricted, statsClient, + allowBackgroundAuthentication, isKeyguardBypassEnabled); + + return id; + } + + @Override + public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) { mHandler.post(() -> mSensors.get(sensorId).getScheduler() - .cancelAuthenticationOrDetection(token)); + .cancelAuthenticationOrDetection(token, requestId)); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java index d05333db7532..f4dcbbba21d7 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java @@ -87,6 +87,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; /** * Supports a single instance of the {@link android.hardware.biometrics.face.V1_0} or its extended @@ -115,6 +116,8 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { @NonNull private final Map<Integer, Long> mAuthenticatorIds; @Nullable private IBiometricsFace mDaemon; @NonNull private final HalResultController mHalResultController; + // for requests that do not use biometric prompt + @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0); private int mCurrentUserId = UserHandle.USER_NULL; private final int mSensorId; private final List<Long> mGeneratedChallengeCount = new ArrayList<>(); @@ -605,7 +608,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { } @Override - public void scheduleFaceDetect(int sensorId, @NonNull IBinder token, + public long scheduleFaceDetect(int sensorId, @NonNull IBinder token, int userId, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, int statsClient) { throw new IllegalStateException("Face detect not supported by IBiometricsFace@1.0. Did you" @@ -613,7 +616,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { } @Override - public void cancelFaceDetect(int sensorId, @NonNull IBinder token) { + public void cancelFaceDetect(int sensorId, @NonNull IBinder token, long requestId) { throw new IllegalStateException("Face detect not supported by IBiometricsFace@1.0. Did you" + "forget to check the supportsFaceDetection flag?"); } @@ -621,26 +624,38 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { @Override public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver, - @NonNull String opPackageName, boolean restricted, int statsClient, + @NonNull String opPackageName, long requestId, boolean restricted, int statsClient, boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) { mHandler.post(() -> { scheduleUpdateActiveUserWithoutHandler(userId); final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorId); final FaceAuthenticationClient client = new FaceAuthenticationClient(mContext, - mLazyDaemon, token, receiver, userId, operationId, restricted, opPackageName, - cookie, false /* requireConfirmation */, mSensorId, isStrongBiometric, - statsClient, mLockoutTracker, mUsageStats, allowBackgroundAuthentication, - isKeyguardBypassEnabled); + mLazyDaemon, token, requestId, receiver, userId, operationId, restricted, + opPackageName, cookie, false /* requireConfirmation */, mSensorId, + isStrongBiometric, statsClient, mLockoutTracker, mUsageStats, + allowBackgroundAuthentication, isKeyguardBypassEnabled); mScheduler.scheduleClientMonitor(client); }); } @Override - public void cancelAuthentication(int sensorId, @NonNull IBinder token) { - mHandler.post(() -> { - mScheduler.cancelAuthenticationOrDetection(token); - }); + public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, + int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver, + @NonNull String opPackageName, boolean restricted, int statsClient, + boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) { + final long id = mRequestCounter.incrementAndGet(); + + scheduleAuthenticate(sensorId, token, operationId, userId, cookie, receiver, + opPackageName, id, restricted, statsClient, + allowBackgroundAuthentication, isKeyguardBypassEnabled); + + return id; + } + + @Override + public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) { + mHandler.post(() -> mScheduler.cancelAuthenticationOrDetection(token, requestId)); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java index 33950af2216f..40f2801541d3 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java @@ -57,7 +57,8 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> { private int mLastAcquire; FaceAuthenticationClient(@NonNull Context context, - @NonNull LazyDaemon<IBiometricsFace> lazyDaemon, @NonNull IBinder token, + @NonNull LazyDaemon<IBiometricsFace> lazyDaemon, + @NonNull IBinder token, long requestId, @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId, boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric, int statsClient, @NonNull LockoutTracker lockoutTracker, @@ -68,6 +69,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> { BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */, lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */, isKeyguardBypassEnabled); + setRequestId(requestId); mUsageStats = usageStats; final Resources resources = getContext().getResources(); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java index 1e5942930b01..52d887a75216 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java @@ -61,10 +61,10 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub @Override public void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, - String opPackageName, int cookie, boolean allowBackgroundAuthentication) + String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication) throws RemoteException { mFingerprintService.prepareForAuthentication(mSensorId, token, operationId, userId, - sensorReceiver, opPackageName, cookie, allowBackgroundAuthentication); + sensorReceiver, opPackageName, requestId, cookie, allowBackgroundAuthentication); } @Override @@ -73,9 +73,10 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub } @Override - public void cancelAuthenticationFromService(IBinder token, String opPackageName) + public void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId) throws RemoteException { - mFingerprintService.cancelAuthenticationFromService(mSensorId, token, opPackageName); + mFingerprintService.cancelAuthenticationFromService( + mSensorId, token, opPackageName, requestId); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index 183fabdc2a7b..f0a8b9ca3146 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -245,7 +245,7 @@ public class FingerprintService extends SystemService { @SuppressWarnings("deprecation") @Override // Binder call - public void authenticate(final IBinder token, final long operationId, + public long authenticate(final IBinder token, final long operationId, final int sensorId, final int userId, final IFingerprintServiceReceiver receiver, final String opPackageName) { final int callingUid = Binder.getCallingUid(); @@ -255,7 +255,7 @@ public class FingerprintService extends SystemService { if (!canUseFingerprint(opPackageName, true /* requireForeground */, callingUid, callingPid, callingUserId)) { Slog.w(TAG, "Authenticate rejecting package: " + opPackageName); - return; + return -1; } // Keyguard check must be done on the caller's binder identity, since it also checks @@ -270,7 +270,7 @@ public class FingerprintService extends SystemService { // SafetyNet for b/79776455 EventLog.writeEvent(0x534e4554, "79776455"); Slog.e(TAG, "Authenticate invoked when user is encrypted or lockdown"); - return; + return -1; } } finally { Binder.restoreCallingIdentity(identity); @@ -290,7 +290,7 @@ public class FingerprintService extends SystemService { } if (provider == null) { Slog.w(TAG, "Null provider for authenticate"); - return; + return -1; } final FingerprintSensorPropertiesInternal sensorProps = @@ -299,18 +299,17 @@ public class FingerprintService extends SystemService { && sensorProps != null && sensorProps.isAnyUdfpsType()) { identity = Binder.clearCallingIdentity(); try { - authenticateWithPrompt(operationId, sensorProps, userId, receiver); + return authenticateWithPrompt(operationId, sensorProps, userId, receiver); } finally { Binder.restoreCallingIdentity(identity); } - } else { - provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, - 0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName, - restricted, statsClient, isKeyguard, mFingerprintStateCallback); } + return provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, + 0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName, + restricted, statsClient, isKeyguard, mFingerprintStateCallback); } - private void authenticateWithPrompt( + private long authenticateWithPrompt( final long operationId, @NonNull final FingerprintSensorPropertiesInternal props, final int userId, @@ -387,33 +386,33 @@ public class FingerprintService extends SystemService { } }; - biometricPrompt.authenticateUserForOperation( + return biometricPrompt.authenticateUserForOperation( new CancellationSignal(), executor, promptCallback, userId, operationId); } @Override - public void detectFingerprint(final IBinder token, final int userId, + public long detectFingerprint(final IBinder token, final int userId, final IFingerprintServiceReceiver receiver, final String opPackageName) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); if (!Utils.isKeyguard(getContext(), opPackageName)) { Slog.w(TAG, "detectFingerprint called from non-sysui package: " + opPackageName); - return; + return -1; } if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) { // If this happens, something in KeyguardUpdateMonitor is wrong. This should only // ever be invoked when the user is encrypted or lockdown. Slog.e(TAG, "detectFingerprint invoked when user is not encrypted or lockdown"); - return; + return -1; } final Pair<Integer, ServiceProvider> provider = getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for detectFingerprint"); - return; + return -1; } - provider.second.scheduleFingerDetect(provider.first, token, userId, + return provider.second.scheduleFingerDetect(provider.first, token, userId, new ClientMonitorCallbackConverter(receiver), opPackageName, BiometricsProtoEnums.CLIENT_KEYGUARD, mFingerprintStateCallback); } @@ -421,7 +420,7 @@ public class FingerprintService extends SystemService { @Override // Binder call public void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, - int cookie, boolean allowBackgroundAuthentication) { + long requestId, int cookie, boolean allowBackgroundAuthentication) { Utils.checkPermission(getContext(), MANAGE_BIOMETRIC); final ServiceProvider provider = getProviderForSensor(sensorId); @@ -432,9 +431,9 @@ public class FingerprintService extends SystemService { final boolean restricted = true; // BiometricPrompt is always restricted provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie, - new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted, - BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication, - mFingerprintStateCallback); + new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, requestId, + restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, + allowBackgroundAuthentication, mFingerprintStateCallback); } @Override // Binder call @@ -452,7 +451,8 @@ public class FingerprintService extends SystemService { @Override // Binder call - public void cancelAuthentication(final IBinder token, final String opPackageName) { + public void cancelAuthentication(final IBinder token, final String opPackageName, + long requestId) { final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); final int callingUserId = UserHandle.getCallingUserId(); @@ -469,11 +469,12 @@ public class FingerprintService extends SystemService { return; } - provider.second.cancelAuthentication(provider.first, token); + provider.second.cancelAuthentication(provider.first, token, requestId); } @Override // Binder call - public void cancelFingerprintDetect(final IBinder token, final String opPackageName) { + public void cancelFingerprintDetect(final IBinder token, final String opPackageName, + final long requestId) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); if (!Utils.isKeyguard(getContext(), opPackageName)) { Slog.w(TAG, "cancelFingerprintDetect called from non-sysui package: " @@ -489,12 +490,12 @@ public class FingerprintService extends SystemService { return; } - provider.second.cancelAuthentication(provider.first, token); + provider.second.cancelAuthentication(provider.first, token, requestId); } @Override // Binder call public void cancelAuthenticationFromService(final int sensorId, final IBinder token, - final String opPackageName) { + final String opPackageName, final long requestId) { Utils.checkPermission(getContext(), MANAGE_BIOMETRIC); @@ -506,7 +507,7 @@ public class FingerprintService extends SystemService { return; } - provider.cancelAuthentication(sensorId, token); + provider.cancelAuthentication(sensorId, token, requestId); } @Override // Binder call diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java index 706ac1013746..b9fcd8ef4e42 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java @@ -95,20 +95,26 @@ public interface ServiceProvider { void cancelEnrollment(int sensorId, @NonNull IBinder token); - void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId, + long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, int statsClient, @NonNull FingerprintStateCallback fingerprintStateCallback); void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback, + @NonNull String opPackageName, long requestId, boolean restricted, int statsClient, + boolean allowBackgroundAuthentication, + @NonNull FingerprintStateCallback fingerprintStateCallback); + + long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, + int cookie, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, boolean restricted, int statsClient, boolean allowBackgroundAuthentication, @NonNull FingerprintStateCallback fingerprintStateCallback); void startPreparedClient(int sensorId, int cookie); - void cancelAuthentication(int sensorId, @NonNull IBinder token); + void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId); void scheduleRemove(int sensorId, @NonNull IBinder token, @NonNull IFingerprintServiceReceiver receiver, int fingerId, int userId, diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java index 37ee76adeece..9d911e0a320b 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java @@ -61,7 +61,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp private boolean mIsPointerDown; FingerprintAuthenticationClient(@NonNull Context context, - @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token, + @NonNull LazyDaemon<ISession> lazyDaemon, + @NonNull IBinder token, long requestId, @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId, boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric, int statsClient, @@ -74,6 +75,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener, lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */, false /* isKeyguardBypassEnabled */); + setRequestId(requestId); mLockoutCache = lockoutCache; mUdfpsOverlayController = udfpsOverlayController; mSensorProps = sensorProps; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java index c5dc44988612..da91cdd981b9 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java @@ -47,13 +47,15 @@ class FingerprintDetectClient extends AcquisitionClient<ISession> implements Det @Nullable private ICancellationSignal mCancellationSignal; FingerprintDetectClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon, - @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, + @NonNull IBinder token, long requestId, + @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner, int sensorId, @Nullable IUdfpsOverlayController udfpsOverlayController, boolean isStrongBiometric, int statsClient) { super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FINGERPRINT, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient); + setRequestId(requestId); mIsStrongBiometric = isStrongBiometric; mUdfpsOverlayController = udfpsOverlayController; } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java index 102b07493134..377fecac6117 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java @@ -71,6 +71,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicLong; /** * Provider for a single instance of the {@link IFingerprint} HAL. @@ -88,6 +89,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher; @NonNull private final ActivityTaskManager mActivityTaskManager; @NonNull private final BiometricTaskStackListener mTaskStackListener; + // for requests that do not use biometric prompt + @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0); @Nullable private IFingerprint mDaemon; @Nullable private IUdfpsOverlayController mUdfpsOverlayController; @@ -118,8 +121,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi && !client.isAlreadyDone()) { Slog.e(getTag(), "Stopping background authentication, top: " + topPackage + " currentClient: " + client); - mSensors.valueAt(i).getScheduler() - .cancelAuthenticationOrDetection(client.getToken()); + mSensors.valueAt(i).getScheduler().cancelAuthenticationOrDetection( + client.getToken(), client.getRequestId()); } } } @@ -369,31 +372,35 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi } @Override - public void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId, + public long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, int statsClient, @NonNull FingerprintStateCallback fingerprintStateCallback) { + final long id = mRequestCounter.incrementAndGet(); + mHandler.post(() -> { final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId); final FingerprintDetectClient client = new FingerprintDetectClient(mContext, - mSensors.get(sensorId).getLazySession(), token, callback, userId, + mSensors.get(sensorId).getLazySession(), token, id, callback, userId, opPackageName, sensorId, mUdfpsOverlayController, isStrongBiometric, statsClient); scheduleForSensor(sensorId, client, fingerprintStateCallback); }); + + return id; } @Override public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback, - @NonNull String opPackageName, boolean restricted, int statsClient, + @NonNull String opPackageName, long requestId, boolean restricted, int statsClient, boolean allowBackgroundAuthentication, @NonNull FingerprintStateCallback fingerprintStateCallback) { mHandler.post(() -> { final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId); final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient( - mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId, - operationId, restricted, opPackageName, cookie, + mContext, mSensors.get(sensorId).getLazySession(), token, requestId, callback, + userId, operationId, restricted, opPackageName, cookie, false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient, mTaskStackListener, mSensors.get(sensorId).getLockoutCache(), mUdfpsOverlayController, allowBackgroundAuthentication, @@ -403,14 +410,29 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi } @Override + public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, + int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback, + @NonNull String opPackageName, boolean restricted, int statsClient, + boolean allowBackgroundAuthentication, + @NonNull FingerprintStateCallback fingerprintStateCallback) { + final long id = mRequestCounter.incrementAndGet(); + + scheduleAuthenticate(sensorId, token, operationId, userId, cookie, callback, + opPackageName, id, restricted, statsClient, allowBackgroundAuthentication, + fingerprintStateCallback); + + return id; + } + + @Override public void startPreparedClient(int sensorId, int cookie) { mHandler.post(() -> mSensors.get(sensorId).getScheduler().startPreparedClient(cookie)); } @Override - public void cancelAuthentication(int sensorId, @NonNull IBinder token) { + public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) { mHandler.post(() -> mSensors.get(sensorId).getScheduler() - .cancelAuthenticationOrDetection(token)); + .cancelAuthenticationOrDetection(token, requestId)); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java index 2f5b5c7b9727..f17bcc8c6354 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java @@ -88,6 +88,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; /** * Supports a single instance of the {@link android.hardware.biometrics.fingerprint.V2_1} or @@ -115,6 +116,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider @NonNull private final HalResultController mHalResultController; @Nullable private IUdfpsOverlayController mUdfpsOverlayController; @Nullable private ISidefpsController mSidefpsController; + // for requests that do not use biometric prompt + @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0); private int mCurrentUserId = UserHandle.USER_NULL; private final boolean mIsUdfps; private final int mSensorId; @@ -142,7 +145,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider && !client.isAlreadyDone()) { Slog.e(TAG, "Stopping background authentication, top: " + topPackage + " currentClient: " + client); - mScheduler.cancelAuthenticationOrDetection(client.getToken()); + mScheduler.cancelAuthenticationOrDetection( + client.getToken(), client.getRequestId()); } } }); @@ -591,26 +595,30 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider } @Override - public void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId, + public long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId, @NonNull ClientMonitorCallbackConverter listener, @NonNull String opPackageName, int statsClient, @NonNull FingerprintStateCallback fingerprintStateCallback) { + final long id = mRequestCounter.incrementAndGet(); + mHandler.post(() -> { scheduleUpdateActiveUserWithoutHandler(userId); final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorProperties.sensorId); final FingerprintDetectClient client = new FingerprintDetectClient(mContext, - mLazyDaemon, token, listener, userId, opPackageName, + mLazyDaemon, token, id, listener, userId, opPackageName, mSensorProperties.sensorId, mUdfpsOverlayController, isStrongBiometric, statsClient); mScheduler.scheduleClientMonitor(client, fingerprintStateCallback); }); + + return id; } @Override public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener, - @NonNull String opPackageName, boolean restricted, int statsClient, + @NonNull String opPackageName, long requestId, boolean restricted, int statsClient, boolean allowBackgroundAuthentication, @NonNull FingerprintStateCallback fingerprintStateCallback) { mHandler.post(() -> { @@ -618,8 +626,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorProperties.sensorId); final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient( - mContext, mLazyDaemon, token, listener, userId, operationId, restricted, - opPackageName, cookie, false /* requireConfirmation */, + mContext, mLazyDaemon, token, requestId, listener, userId, operationId, + restricted, opPackageName, cookie, false /* requireConfirmation */, mSensorProperties.sensorId, isStrongBiometric, statsClient, mTaskStackListener, mLockoutTracker, mUdfpsOverlayController, allowBackgroundAuthentication, mSensorProperties); @@ -628,14 +636,29 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider } @Override + public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, + int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener, + @NonNull String opPackageName, boolean restricted, int statsClient, + boolean allowBackgroundAuthentication, + @NonNull FingerprintStateCallback fingerprintStateCallback) { + final long id = mRequestCounter.incrementAndGet(); + + scheduleAuthenticate(sensorId, token, operationId, userId, cookie, listener, + opPackageName, id, restricted, statsClient, allowBackgroundAuthentication, + fingerprintStateCallback); + + return id; + } + + @Override public void startPreparedClient(int sensorId, int cookie) { mHandler.post(() -> mScheduler.startPreparedClient(cookie)); } @Override - public void cancelAuthentication(int sensorId, @NonNull IBinder token) { + public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) { Slog.d(TAG, "cancelAuthentication, sensorId: " + sensorId); - mHandler.post(() -> mScheduler.cancelAuthenticationOrDetection(token)); + mHandler.post(() -> mScheduler.cancelAuthenticationOrDetection(token, requestId)); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java index 5060744bb33e..7d95ec098fee 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java @@ -59,7 +59,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi private boolean mIsPointerDown; FingerprintAuthenticationClient(@NonNull Context context, - @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token, + @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, + @NonNull IBinder token, long requestId, @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId, boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric, int statsClient, @@ -73,6 +74,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener, lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */, false /* isKeyguardBypassEnabled */); + setRequestId(requestId); mLockoutFrameworkImpl = lockoutTracker; mUdfpsOverlayController = udfpsOverlayController; mSensorProps = sensorProps; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java index 8e73ee6b3e9f..147a20699b54 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java @@ -52,13 +52,15 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint> private boolean mIsPointerDown; public FingerprintDetectClient(@NonNull Context context, - @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token, + @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, + @NonNull IBinder token, long requestId, @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner, int sensorId, @Nullable IUdfpsOverlayController udfpsOverlayController, boolean isStrongBiometric, int statsClient) { super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FINGERPRINT, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient); + setRequestId(requestId); mUdfpsOverlayController = udfpsOverlayController; mIsStrongBiometric = isStrongBiometric; } diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java index 491818520e3c..5c0c3626037a 100644 --- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java @@ -59,7 +59,7 @@ public final class IrisAuthenticator extends IBiometricAuthenticator.Stub { @Override public void prepareForAuthentication(boolean requireConfirmation, IBinder token, long sessionId, int userId, IBiometricSensorReceiver sensorReceiver, - String opPackageName, int cookie, boolean allowBackgroundAuthentication) + String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication) throws RemoteException { } @@ -68,7 +68,7 @@ public final class IrisAuthenticator extends IBiometricAuthenticator.Stub { } @Override - public void cancelAuthenticationFromService(IBinder token, String opPackageName) + public void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId) throws RemoteException { } diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index d66d7ee99f2e..5797b061f2d0 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -36,9 +36,14 @@ import android.hardware.display.DisplayManagerInternal.RefreshRateRange; import android.hardware.fingerprint.IUdfpsHbmListener; import android.net.Uri; import android.os.Handler; +import android.os.IThermalEventListener; +import android.os.IThermalService; import android.os.Looper; import android.os.Message; +import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemClock; +import android.os.Temperature; import android.os.UserHandle; import android.provider.DeviceConfig; import android.provider.Settings; @@ -108,6 +113,7 @@ public class DisplayModeDirector { private final UdfpsObserver mUdfpsObserver; private final SensorObserver mSensorObserver; private final HbmObserver mHbmObserver; + private final SkinThermalStatusObserver mSkinThermalStatusObserver; private final DeviceConfigInterface mDeviceConfig; private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings; @@ -156,6 +162,7 @@ public class DisplayModeDirector { }; mSensorObserver = new SensorObserver(context, ballotBox, injector); mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler()); + mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, ballotBox); mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings(); mDeviceConfig = injector.getDeviceConfig(); mAlwaysRespectAppRequest = false; @@ -174,6 +181,7 @@ public class DisplayModeDirector { mBrightnessObserver.observe(sensorManager); mSensorObserver.observe(); mHbmObserver.observe(); + mSkinThermalStatusObserver.observe(); synchronized (mLock) { // We may have a listener already registered before the call to start, so go ahead and // notify them to pick up our newly initialized state. @@ -606,6 +614,7 @@ public class DisplayModeDirector { mUdfpsObserver.dumpLocked(pw); mSensorObserver.dumpLocked(pw); mHbmObserver.dumpLocked(pw); + mSkinThermalStatusObserver.dumpLocked(pw); } } @@ -714,7 +723,6 @@ public class DisplayModeDirector { return mUdfpsObserver; } - @VisibleForTesting DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings( float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) { @@ -950,16 +958,19 @@ public class DisplayModeDirector { // user seeing the display flickering when the switches occur. public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8; + // Force display to [0, 60HZ] if skin temperature is at or above CRITICAL. + public static final int PRIORITY_SKIN_TEMPERATURE = 9; + // High-brightness-mode may need a specific range of refresh-rates to function properly. - public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 9; + public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 10; // The proximity sensor needs the refresh rate to be locked in order to function, so this is // set to a high priority. - public static final int PRIORITY_PROXIMITY = 10; + public static final int PRIORITY_PROXIMITY = 11; // The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order // to function, so this needs to be the highest priority of all votes. - public static final int PRIORITY_UDFPS = 11; + public static final int PRIORITY_UDFPS = 12; // Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and // APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString. @@ -1054,6 +1065,8 @@ public class DisplayModeDirector { return "PRIORITY_PROXIMITY"; case PRIORITY_LOW_POWER_MODE: return "PRIORITY_LOW_POWER_MODE"; + case PRIORITY_SKIN_TEMPERATURE: + return "PRIORITY_SKIN_TEMPERATURE"; case PRIORITY_UDFPS: return "PRIORITY_UDFPS"; case PRIORITY_USER_SETTING_MIN_REFRESH_RATE: @@ -2309,6 +2322,52 @@ public class DisplayModeDirector { } } + private final class SkinThermalStatusObserver extends IThermalEventListener.Stub { + private final BallotBox mBallotBox; + private final Injector mInjector; + + private @Temperature.ThrottlingStatus int mStatus = -1; + + SkinThermalStatusObserver(Injector injector, BallotBox ballotBox) { + mInjector = injector; + mBallotBox = ballotBox; + } + + @Override + public void notifyThrottling(Temperature temp) { + mStatus = temp.getStatus(); + if (mLoggingEnabled) { + Slog.d(TAG, "New thermal throttling status " + + ", current thermal status = " + mStatus); + } + final Vote vote; + if (mStatus >= Temperature.THROTTLING_CRITICAL) { + vote = Vote.forRefreshRates(0f, 60f); + } else { + vote = null; + } + mBallotBox.vote(GLOBAL_ID, Vote.PRIORITY_SKIN_TEMPERATURE, vote); + } + + public void observe() { + IThermalService thermalService = mInjector.getThermalService(); + if (thermalService == null) { + Slog.w(TAG, "Could not observe thermal status. Service not available"); + return; + } + try { + thermalService.registerThermalEventListenerWithType(this, Temperature.TYPE_SKIN); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to register thermal status listener", e); + } + } + + void dumpLocked(PrintWriter writer) { + writer.println(" SkinThermalStatusObserver:"); + writer.println(" mStatus: " + mStatus); + } + } + private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener { public DeviceConfigDisplaySettings() { } @@ -2470,6 +2529,8 @@ public class DisplayModeDirector { BrightnessInfo getBrightnessInfo(int displayId); boolean isDozeState(Display d); + + IThermalService getThermalService(); } @VisibleForTesting @@ -2530,6 +2591,12 @@ public class DisplayModeDirector { return Display.isDozeState(d.getState()); } + @Override + public IThermalService getThermalService() { + return IThermalService.Stub.asInterface( + ServiceManager.getService(Context.THERMAL_SERVICE)); + } + private DisplayManager getDisplayManager() { if (mDisplayManager == null) { mDisplayManager = mContext.getSystemService(DisplayManager.class); diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 3a7e13b8d872..abe81e139b43 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -783,13 +783,14 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D @Override public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, - int userId, String opPackageName, long operationId, + int userId, long operationId, String opPackageName, long requestId, @BiometricMultiSensorMode int multiSensorConfig) { enforceBiometricDialog(); if (mBar != null) { try { mBar.showAuthenticationDialog(promptInfo, receiver, sensorIds, credentialAllowed, - requireConfirmation, userId, opPackageName, operationId, multiSensorConfig); + requireConfirmation, userId, operationId, opPackageName, requestId, + multiSensorConfig); } catch (RemoteException ex) { } } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 73d31bf7e0c8..94465ac21dff 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -355,6 +355,8 @@ public class DisplayPolicy { private PointerLocationView mPointerLocationView; + private int mDisplayCutoutTouchableRegionSize; + /** * The area covered by system windows which belong to another display. Forwarded insets is set * in case this is a virtual display, this is displayed on another display that has insets, and @@ -1081,8 +1083,21 @@ public class DisplayPolicy { (displayFrames, windowState, rect) -> { rect.bottom = rect.top + getStatusBarHeight(displayFrames); }; + final TriConsumer<DisplayFrames, WindowState, Rect> gestureFrameProvider = + (displayFrames, windowState, rect) -> { + rect.bottom = rect.top + getStatusBarHeight(displayFrames); + final DisplayCutout cutout = + displayFrames.mInsetsState.getDisplayCutout(); + if (cutout != null) { + final Rect top = cutout.getBoundingRectTop(); + if (!top.isEmpty()) { + rect.bottom = rect.bottom + mDisplayCutoutTouchableRegionSize; + } + } + }; mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, win, frameProvider); - mDisplayContent.setInsetProvider(ITYPE_TOP_MANDATORY_GESTURES, win, frameProvider); + mDisplayContent.setInsetProvider( + ITYPE_TOP_MANDATORY_GESTURES, win, gestureFrameProvider); mDisplayContent.setInsetProvider(ITYPE_TOP_TAPPABLE_ELEMENT, win, frameProvider); break; case TYPE_NAVIGATION_BAR: @@ -1993,11 +2008,14 @@ public class DisplayPolicy { mStatusBarHeightForRotation[landscapeRotation] = mStatusBarHeightForRotation[seascapeRotation] = res.getDimensionPixelSize(R.dimen.status_bar_height_landscape); + mDisplayCutoutTouchableRegionSize = res.getDimensionPixelSize( + R.dimen.display_cutout_touchable_region_size); } else { mStatusBarHeightForRotation[portraitRotation] = mStatusBarHeightForRotation[upsideDownRotation] = mStatusBarHeightForRotation[landscapeRotation] = mStatusBarHeightForRotation[seascapeRotation] = 0; + mDisplayCutoutTouchableRegionSize = 0; } // Height of the navigation bar when presented horizontally at bottom 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 2892bf58a7d2..b3f7587df612 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java @@ -74,6 +74,7 @@ import java.util.function.Consumer; public class AuthSessionTest { private static final String TEST_PACKAGE = "test_package"; + private static final long TEST_REQUEST_ID = 22; @Mock private Context mContext; @Mock private ITrustManager mTrustManager; @@ -112,6 +113,7 @@ public class AuthSessionTest { final AuthSession session = createAuthSession(mSensors, false /* checkDevicePolicyManager */, Authenticators.BIOMETRIC_STRONG, + TEST_REQUEST_ID, 0 /* operationId */, 0 /* userId */); @@ -133,6 +135,7 @@ public class AuthSessionTest { final AuthSession session = createAuthSession(mSensors, false /* checkDevicePolicyManager */, Authenticators.BIOMETRIC_STRONG, + TEST_REQUEST_ID, operationId, userId); assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size()); @@ -153,6 +156,7 @@ public class AuthSessionTest { eq(userId), eq(mSensorReceiver), eq(TEST_PACKAGE), + eq(TEST_REQUEST_ID), eq(sensor.getCookie()), anyBoolean() /* allowBackgroundAuthentication */); } @@ -185,6 +189,33 @@ public class AuthSessionTest { } @Test + public void testCancelReducesAppetiteForCookies() throws Exception { + setupFace(0 /* id */, false /* confirmationAlwaysRequired */, + mock(IBiometricAuthenticator.class)); + setupFingerprint(1 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL); + + final AuthSession session = createAuthSession(mSensors, + false /* checkDevicePolicyManager */, + Authenticators.BIOMETRIC_STRONG, + TEST_REQUEST_ID, + 44 /* operationId */, + 2 /* userId */); + + session.goToInitialState(); + + for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { + assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState()); + } + + session.onCancelAuthSession(false /* force */); + + for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { + session.onCookieReceived(sensor.getCookie()); + assertEquals(BiometricSensor.STATE_CANCELING, sensor.getSensorState()); + } + } + + @Test public void testMultiAuth_singleSensor_fingerprintSensorStartsAfterDialogAnimationCompletes() throws Exception { setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL); @@ -212,6 +243,7 @@ public class AuthSessionTest { final AuthSession session = createAuthSession(mSensors, false /* checkDevicePolicyManager */, Authenticators.BIOMETRIC_STRONG, + TEST_REQUEST_ID, operationId, userId); assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size()); @@ -238,7 +270,7 @@ public class AuthSessionTest { // fingerprint sensor does not start even if all cookies are received assertEquals(STATE_AUTH_STARTED, session.getState()); verify(mStatusBarService).showAuthenticationDialog(any(), any(), any(), - anyBoolean(), anyBoolean(), anyInt(), any(), anyLong(), anyInt()); + anyBoolean(), anyBoolean(), anyInt(), anyLong(), any(), anyLong(), anyInt()); // Notify AuthSession that the UI is shown. Then, fingerprint sensor should be started. session.onDialogAnimatedIn(); @@ -277,6 +309,7 @@ public class AuthSessionTest { final AuthSession session = createAuthSession(mSensors, false /* checkDevicePolicyManager */, Authenticators.BIOMETRIC_STRONG, + TEST_REQUEST_ID, 0 /* operationId */, 0 /* userId */); @@ -285,7 +318,8 @@ public class AuthSessionTest { sessionConsumer.accept(session); - verify(faceAuthenticator).cancelAuthenticationFromService(eq(mToken), eq(TEST_PACKAGE)); + verify(faceAuthenticator).cancelAuthenticationFromService( + eq(mToken), eq(TEST_PACKAGE), eq(TEST_REQUEST_ID)); } private PreAuthInfo createPreAuthInfo(List<BiometricSensor> sensors, int userId, @@ -302,14 +336,14 @@ public class AuthSessionTest { private AuthSession createAuthSession(List<BiometricSensor> sensors, boolean checkDevicePolicyManager, @Authenticators.Types int authenticators, - long operationId, int userId) throws RemoteException { + long requestId, long operationId, int userId) throws RemoteException { final PromptInfo promptInfo = createPromptInfo(authenticators); final PreAuthInfo preAuthInfo = createPreAuthInfo(sensors, userId, promptInfo, checkDevicePolicyManager); return new AuthSession(mContext, mStatusBarService, mSysuiReceiver, mKeyStore, - mRandom, mClientDeathReceiver, preAuthInfo, mToken, operationId, userId, + mRandom, mClientDeathReceiver, preAuthInfo, mToken, requestId, operationId, userId, mSensorReceiver, mClientReceiver, TEST_PACKAGE, promptInfo, false /* debugEnabled */, mFingerprintSensorProps); } 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 7c7afb7dde36..69d8e89ac3b3 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java @@ -85,6 +85,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.Random; +import java.util.concurrent.atomic.AtomicLong; @Presubmit @SmallTest @@ -93,6 +94,7 @@ public class BiometricServiceTest { private static final String TAG = "BiometricServiceTest"; private static final String TEST_PACKAGE_NAME = "test_package"; + private static final long TEST_REQUEST_ID = 44; private static final String ERROR_HW_UNAVAILABLE = "hw_unavailable"; private static final String ERROR_NOT_RECOGNIZED = "not_recognized"; @@ -151,6 +153,7 @@ public class BiometricServiceTest { .thenReturn(mock(BiometricStrengthController.class)); when(mInjector.getTrustManager()).thenReturn(mTrustManager); when(mInjector.getDevicePolicyManager(any())).thenReturn(mDevicePolicyManager); + when(mInjector.getRequestGenerator()).thenReturn(new AtomicLong(TEST_REQUEST_ID - 1)); when(mResources.getString(R.string.biometric_error_hw_unavailable)) .thenReturn(ERROR_HW_UNAVAILABLE); @@ -215,8 +218,7 @@ public class BiometricServiceTest { mBiometricService.mCurrentAuthSession.getState()); verify(mBiometricService.mCurrentAuthSession.mPreAuthInfo.eligibleSensors.get(0).impl) - .cancelAuthenticationFromService(any(), - any()); + .cancelAuthenticationFromService(any(), any(), anyLong()); // Simulate ERROR_CANCELED received from HAL mBiometricService.mBiometricSensorReceiver.onError( @@ -272,8 +274,9 @@ public class BiometricServiceTest { eq(true) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, eq(TEST_PACKAGE_NAME), - anyLong() /* sessionId */, + eq(TEST_REQUEST_ID), eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); } @@ -357,8 +360,9 @@ public class BiometricServiceTest { eq(false) /* credentialAllowed */, eq(false) /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, eq(TEST_PACKAGE_NAME), - anyLong() /* sessionId */, + eq(TEST_REQUEST_ID), eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); } @@ -467,6 +471,7 @@ public class BiometricServiceTest { anyInt() /* userId */, any(IBiometricSensorReceiver.class), anyString() /* opPackageName */, + eq(TEST_REQUEST_ID), cookieCaptor.capture() /* cookie */, anyBoolean() /* allowBackgroundAuthentication */); @@ -488,8 +493,9 @@ public class BiometricServiceTest { eq(false) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, eq(TEST_PACKAGE_NAME), - anyLong() /* sessionId */, + eq(TEST_REQUEST_ID), eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); // Hardware authenticated @@ -543,8 +549,9 @@ public class BiometricServiceTest { eq(true) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, eq(TEST_PACKAGE_NAME), - anyLong() /* sessionId */, + eq(TEST_REQUEST_ID), eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); } @@ -705,8 +712,9 @@ public class BiometricServiceTest { anyBoolean() /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, anyString(), - anyLong() /* sessionId */, + anyLong() /* requestId */, eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); } @@ -805,8 +813,9 @@ public class BiometricServiceTest { eq(true) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, eq(TEST_PACKAGE_NAME), - anyLong() /* sessionId */, + eq(TEST_REQUEST_ID), eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); } @@ -885,8 +894,9 @@ public class BiometricServiceTest { eq(true) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, eq(TEST_PACKAGE_NAME), - anyLong() /* sessionId */, + eq(TEST_REQUEST_ID), eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); } @@ -1030,8 +1040,7 @@ public class BiometricServiceTest { eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED), eq(0 /* vendorCode */)); verify(mBiometricService.mSensors.get(0).impl).cancelAuthenticationFromService( - any(), - any()); + any(), any(), anyLong()); assertNull(mBiometricService.mCurrentAuthSession); } @@ -1051,7 +1060,7 @@ public class BiometricServiceTest { waitForIdle(); verify(mBiometricService.mSensors.get(0).impl) - .cancelAuthenticationFromService(any(), any()); + .cancelAuthenticationFromService(any(), any(), anyLong()); } @Test @@ -1071,7 +1080,7 @@ public class BiometricServiceTest { waitForIdle(); verify(mBiometricService.mSensors.get(0).impl) - .cancelAuthenticationFromService(any(), any()); + .cancelAuthenticationFromService(any(), any(), anyLong()); } @Test @@ -1088,7 +1097,7 @@ public class BiometricServiceTest { waitForIdle(); verify(mBiometricService.mSensors.get(0).impl) - .cancelAuthenticationFromService(any(), any()); + .cancelAuthenticationFromService(any(), any(), anyLong()); verify(mReceiver1).onError( eq(BiometricAuthenticator.TYPE_FACE), eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED), @@ -1126,7 +1135,7 @@ public class BiometricServiceTest { false /* requireConfirmation */, null /* authenticators */); mBiometricService.mImpl.cancelAuthentication(mBiometricService.mCurrentAuthSession.mToken, - TEST_PACKAGE_NAME); + TEST_PACKAGE_NAME, TEST_REQUEST_ID); waitForIdle(); // Pretend that the HAL has responded to cancel with ERROR_CANCELED @@ -1353,8 +1362,8 @@ public class BiometricServiceTest { int authenticators = Authenticators.BIOMETRIC_STRONG; assertEquals(BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED, invokeCanAuthenticate(mBiometricService, authenticators)); - invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, - authenticators); + long requestId = invokeAuthenticate(mBiometricService.mImpl, mReceiver1, + false /* requireConfirmation */, authenticators); waitForIdle(); verify(mReceiver1).onError( eq(BiometricAuthenticator.TYPE_FINGERPRINT), @@ -1366,7 +1375,7 @@ public class BiometricServiceTest { authenticators = Authenticators.BIOMETRIC_WEAK; assertEquals(BiometricManager.BIOMETRIC_SUCCESS, invokeCanAuthenticate(mBiometricService, authenticators)); - invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, + requestId = invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, authenticators); waitForIdle(); @@ -1377,8 +1386,9 @@ public class BiometricServiceTest { eq(false) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, eq(TEST_PACKAGE_NAME), - anyLong() /* sessionId */, + eq(requestId), eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); // Requesting strong and credential, when credential is setup @@ -1387,7 +1397,7 @@ public class BiometricServiceTest { when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true); assertEquals(BiometricManager.BIOMETRIC_SUCCESS, invokeCanAuthenticate(mBiometricService, authenticators)); - invokeAuthenticate(mBiometricService.mImpl, mReceiver1, + requestId = invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, authenticators); waitForIdle(); @@ -1399,8 +1409,9 @@ public class BiometricServiceTest { eq(true) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, eq(TEST_PACKAGE_NAME), - anyLong() /* sessionId */, + eq(requestId), eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); // Un-downgrading the authenticator allows successful strong auth @@ -1414,7 +1425,7 @@ public class BiometricServiceTest { authenticators = Authenticators.BIOMETRIC_STRONG; assertEquals(BiometricManager.BIOMETRIC_SUCCESS, invokeCanAuthenticate(mBiometricService, authenticators)); - invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, + requestId = invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, authenticators); waitForIdle(); verify(mBiometricService.mStatusBarService).showAuthenticationDialog( @@ -1424,8 +1435,9 @@ public class BiometricServiceTest { eq(false) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, eq(TEST_PACKAGE_NAME), - anyLong() /* sessionId */, + eq(requestId), eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); } @@ -1617,11 +1629,12 @@ public class BiometricServiceTest { mBiometricService.mStatusBarService = mock(IStatusBarService.class); } - private void invokeAuthenticateAndStart(IBiometricService.Stub service, + private long invokeAuthenticateAndStart(IBiometricService.Stub service, IBiometricServiceReceiver receiver, boolean requireConfirmation, Integer authenticators) throws Exception { // Request auth, creates a pending session - invokeAuthenticate(service, receiver, requireConfirmation, authenticators); + final long requestId = invokeAuthenticate( + service, receiver, requireConfirmation, authenticators); waitForIdle(); startPendingAuthSession(mBiometricService); @@ -1629,6 +1642,8 @@ public class BiometricServiceTest { assertNotNull(mBiometricService.mCurrentAuthSession); assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState()); + + return requestId; } private static void startPendingAuthSession(BiometricService service) throws Exception { @@ -1644,10 +1659,10 @@ public class BiometricServiceTest { service.mImpl.onReadyForAuthentication(cookie); } - private static void invokeAuthenticate(IBiometricService.Stub service, + private static long invokeAuthenticate(IBiometricService.Stub service, IBiometricServiceReceiver receiver, boolean requireConfirmation, Integer authenticators) throws Exception { - service.authenticate( + return service.authenticate( new Binder() /* token */, 0 /* operationId */, 0 /* userId */, @@ -1657,9 +1672,9 @@ public class BiometricServiceTest { false /* checkDevicePolicy */)); } - private static void invokeAuthenticateForWorkApp(IBiometricService.Stub service, + private static long invokeAuthenticateForWorkApp(IBiometricService.Stub service, IBiometricServiceReceiver receiver, Integer authenticators) throws Exception { - service.authenticate( + return service.authenticate( new Binder() /* token */, 0 /* operationId */, 0 /* userId */, diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java index a41f79e8f682..e3e3900c47e0 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java @@ -40,6 +40,7 @@ import android.platform.test.annotations.Presubmit; import android.testing.TestableContext; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -193,7 +194,7 @@ public class BiometricSchedulerTest { // Request it to be canceled. The operation can be canceled immediately, and the scheduler // should go back to idle, since in this case the framework has not even requested the HAL // to authenticate yet. - mScheduler.cancelAuthenticationOrDetection(mToken); + mScheduler.cancelAuthenticationOrDetection(mToken, 1 /* requestId */); assertNull(mScheduler.mCurrentOperation); } @@ -303,7 +304,7 @@ public class BiometricSchedulerTest { mScheduler.mPendingOperations.getFirst().mState); // Request cancel before the authentication client has started - mScheduler.cancelAuthenticationOrDetection(mToken); + mScheduler.cancelAuthenticationOrDetection(mToken, 1 /* requestId */); waitForIdle(); assertEquals(Operation.STATE_WAITING_IN_QUEUE_CANCELING, mScheduler.mPendingOperations.getFirst().mState); @@ -318,6 +319,107 @@ public class BiometricSchedulerTest { } @Test + public void testCancels_whenAuthRequestIdNotSet() { + testCancelsWhenRequestId(null /* requestId */, 2, true /* started */); + } + + @Test + public void testCancels_whenAuthRequestIdNotSet_notStarted() { + testCancelsWhenRequestId(null /* requestId */, 2, false /* started */); + } + + @Test + public void testCancels_whenAuthRequestIdMatches() { + testCancelsWhenRequestId(200L, 200, true /* started */); + } + + @Test + public void testCancels_whenAuthRequestIdMatches_noStarted() { + testCancelsWhenRequestId(200L, 200, false /* started */); + } + + @Test + public void testDoesNotCancel_whenAuthRequestIdMismatched() { + testCancelsWhenRequestId(10L, 20, true /* started */); + } + + @Test + public void testDoesNotCancel_whenAuthRequestIdMismatched_notStarted() { + testCancelsWhenRequestId(10L, 20, false /* started */); + } + + private void testCancelsWhenRequestId(@Nullable Long requestId, long cancelRequestId, + boolean started) { + final boolean matches = requestId == null || requestId == cancelRequestId; + final HalClientMonitor.LazyDaemon<Object> lazyDaemon = () -> mock(Object.class); + final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class); + final TestAuthenticationClient client = new TestAuthenticationClient( + mContext, lazyDaemon, mToken, callback); + if (requestId != null) { + client.setRequestId(requestId); + } + + mScheduler.scheduleClientMonitor(client); + if (started) { + mScheduler.startPreparedClient(client.getCookie()); + } + waitForIdle(); + mScheduler.cancelAuthenticationOrDetection(mToken, cancelRequestId); + waitForIdle(); + + assertEquals(matches && started ? 1 : 0, client.mNumCancels); + + if (matches) { + if (started) { + assertEquals(Operation.STATE_STARTED_CANCELING, + mScheduler.mCurrentOperation.mState); + } + } else { + if (started) { + assertEquals(Operation.STATE_STARTED, + mScheduler.mCurrentOperation.mState); + } else { + assertEquals(Operation.STATE_WAITING_FOR_COOKIE, + mScheduler.mCurrentOperation.mState); + } + } + } + + @Test + public void testCancelsPending_whenAuthRequestIdsSet() { + final long requestId1 = 10; + final long requestId2 = 20; + final HalClientMonitor.LazyDaemon<Object> lazyDaemon = () -> mock(Object.class); + final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class); + final TestAuthenticationClient client1 = new TestAuthenticationClient( + mContext, lazyDaemon, mToken, callback); + client1.setRequestId(requestId1); + final TestAuthenticationClient client2 = new TestAuthenticationClient( + mContext, lazyDaemon, mToken, callback); + client2.setRequestId(requestId2); + + mScheduler.scheduleClientMonitor(client1); + mScheduler.scheduleClientMonitor(client2); + mScheduler.startPreparedClient(client1.getCookie()); + waitForIdle(); + mScheduler.cancelAuthenticationOrDetection(mToken, 9999); + waitForIdle(); + + assertEquals(Operation.STATE_STARTED, + mScheduler.mCurrentOperation.mState); + assertEquals(Operation.STATE_WAITING_IN_QUEUE, + mScheduler.mPendingOperations.getFirst().mState); + + mScheduler.cancelAuthenticationOrDetection(mToken, requestId2); + waitForIdle(); + + assertEquals(Operation.STATE_STARTED, + mScheduler.mCurrentOperation.mState); + assertEquals(Operation.STATE_WAITING_IN_QUEUE_CANCELING, + mScheduler.mPendingOperations.getFirst().mState); + } + + @Test public void testInterruptPrecedingClients_whenExpected() { final BaseClientMonitor interruptableMonitor = mock(BaseClientMonitor.class, withSettings().extraInterfaces(Interruptable.class)); @@ -377,12 +479,10 @@ public class BiometricSchedulerTest { @Override protected void stopHalOperation() { - } @Override protected void startHalOperation() { - } @Override @@ -397,6 +497,7 @@ public class BiometricSchedulerTest { } private static class TestAuthenticationClient extends AuthenticationClient<Object> { + int mNumCancels = 0; public TestAuthenticationClient(@NonNull Context context, @NonNull LazyDaemon<Object> lazyDaemon, @NonNull IBinder token, @@ -428,6 +529,11 @@ public class BiometricSchedulerTest { public boolean wasUserDetected() { return false; } + + public void cancel() { + mNumCancels++; + super.cancel(); + } } private static class TestClientMonitor2 extends TestClientMonitor { diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java index 1ac28abb4c2f..4564296810ff 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java @@ -56,7 +56,11 @@ import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation; import android.hardware.display.DisplayManagerInternal.RefreshRateRange; import android.hardware.fingerprint.IUdfpsHbmListener; import android.os.Handler; +import android.os.IThermalEventListener; +import android.os.IThermalService; import android.os.Looper; +import android.os.RemoteException; +import android.os.Temperature; import android.provider.DeviceConfig; import android.provider.Settings; import android.test.mock.MockContentResolver; @@ -116,6 +120,8 @@ public class DisplayModeDirectorTest { public SensorManagerInternal mSensorManagerInternalMock; @Mock public DisplayManagerInternal mDisplayManagerInternalMock; + @Mock + public IThermalService mThermalServiceMock; @Before public void setUp() throws Exception { @@ -124,6 +130,7 @@ public class DisplayModeDirectorTest { final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext); when(mContext.getContentResolver()).thenReturn(resolver); mInjector = spy(new FakesInjector()); + when(mInjector.getThermalService()).thenReturn(mThermalServiceMock); mHandler = new Handler(Looper.getMainLooper()); LocalServices.removeServiceForTest(StatusBarManagerInternal.class); @@ -1547,12 +1554,52 @@ public class DisplayModeDirectorTest { assertNull(vote); } + @Test + public void testSkinTemperature() throws RemoteException { + DisplayModeDirector director = + createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0); + director.start(createMockSensorManager()); + + ArgumentCaptor<IThermalEventListener> thermalEventListener = + ArgumentCaptor.forClass(IThermalEventListener.class); + + verify(mThermalServiceMock).registerThermalEventListenerWithType( + thermalEventListener.capture(), eq(Temperature.TYPE_SKIN)); + final IThermalEventListener listener = thermalEventListener.getValue(); + + // Verify that there is no skin temperature vote initially. + Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE); + assertNull(vote); + + // Set the skin temperature to critical and verify that we added a vote. + listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_CRITICAL)); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE); + assertVoteForRefreshRateRange(vote, 0f, 60.f); + + // Set the skin temperature to severe and verify that the vote is gone. + listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_SEVERE)); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE); + assertNull(vote); + } + + private Temperature getSkinTemp(@Temperature.ThrottlingStatus int status) { + return new Temperature(30.0f, Temperature.TYPE_SKIN, "test_skin_temp", status); + } + private void assertVoteForRefreshRate(Vote vote, float refreshRate) { assertThat(vote).isNotNull(); final RefreshRateRange expectedRange = new RefreshRateRange(refreshRate, refreshRate); assertThat(vote.refreshRateRange).isEqualTo(expectedRange); } + private void assertVoteForRefreshRateRange( + Vote vote, float refreshRateLow, float refreshRateHigh) { + assertThat(vote).isNotNull(); + final RefreshRateRange expectedRange = + new RefreshRateRange(refreshRateLow, refreshRateHigh); + assertThat(vote.refreshRateRange).isEqualTo(expectedRange); + } + public static class FakeDeviceConfig extends FakeDeviceConfigInterface { @Override public String getProperty(String namespace, String name) { @@ -1748,6 +1795,11 @@ public class DisplayModeDirectorTest { return false; } + @Override + public IThermalService getThermalService() { + return null; + } + void notifyPeakRefreshRateChanged() { if (mPeakRefreshRateObserver != null) { mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/, diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 255a61266ebf..8f3172a14074 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -3483,7 +3483,8 @@ public class TelephonyManager { */ private int getLogicalSlotIndex(int physicalSlotIndex) { UiccSlotInfo[] slotInfos = getUiccSlotsInfo(); - if (slotInfos != null && physicalSlotIndex >= 0 && physicalSlotIndex < slotInfos.length) { + if (slotInfos != null && physicalSlotIndex >= 0 && physicalSlotIndex < slotInfos.length + && slotInfos[physicalSlotIndex] != null) { return slotInfos[physicalSlotIndex].getLogicalSlotIdx(); } |