Merge "Handle cancellation properly for setDeviceCredentialAllowed(true)" into qt-dev
am: 76d5454a86
Change-Id: I1c6d9c51e6af91a79bf34d4d7245f758993a365e
This commit is contained in:
@@ -161,6 +161,7 @@ java_defaults {
|
||||
":libcamera_client_framework_aidl",
|
||||
"core/java/android/hardware/IConsumerIrService.aidl",
|
||||
"core/java/android/hardware/ISerialManager.aidl",
|
||||
"core/java/android/hardware/biometrics/IBiometricConfirmDeviceCredentialCallback.aidl",
|
||||
"core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl",
|
||||
"core/java/android/hardware/biometrics/IBiometricService.aidl",
|
||||
"core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl",
|
||||
|
||||
@@ -207,5 +207,22 @@ public class BiometricManager {
|
||||
Slog.w(TAG, "onConfirmDeviceCredentialError(): Service not connected");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO(b/123378871): Remove when moved.
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
|
||||
public void registerCancellationCallback(IBiometricConfirmDeviceCredentialCallback callback) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
mService.registerCancellationCallback(callback);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
} else {
|
||||
Slog.w(TAG, "registerCancellationCallback(): Service not connected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,11 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
||||
* @hide
|
||||
*/
|
||||
public static final String KEY_ALLOW_DEVICE_CREDENTIAL = "allow_device_credential";
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final String KEY_FROM_CONFIRM_DEVICE_CREDENTIAL
|
||||
= "from_confirm_device_credential";
|
||||
|
||||
/**
|
||||
* Error/help message will show for this amount of time.
|
||||
@@ -270,6 +275,17 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO(123378871): Remove when moved.
|
||||
* @return
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
|
||||
@NonNull public Builder setFromConfirmDeviceCredential() {
|
||||
mBundle.putBoolean(KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link BiometricPrompt}.
|
||||
* @return a {@link BiometricPrompt}
|
||||
@@ -494,7 +510,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
||||
public void authenticateUser(@NonNull CancellationSignal cancel,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull AuthenticationCallback callback,
|
||||
int userId) {
|
||||
int userId,
|
||||
IBiometricConfirmDeviceCredentialCallback confirmDeviceCredentialCallback) {
|
||||
if (cancel == null) {
|
||||
throw new IllegalArgumentException("Must supply a cancellation signal");
|
||||
}
|
||||
@@ -504,7 +521,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("Must supply a callback");
|
||||
}
|
||||
authenticateInternal(null /* crypto */, cancel, executor, callback, userId);
|
||||
authenticateInternal(null /* crypto */, cancel, executor, callback, userId,
|
||||
confirmDeviceCredentialCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -555,7 +573,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
||||
if (mBundle.getBoolean(KEY_ALLOW_DEVICE_CREDENTIAL)) {
|
||||
throw new IllegalArgumentException("Device credential not supported with crypto");
|
||||
}
|
||||
authenticateInternal(crypto, cancel, executor, callback, mContext.getUserId());
|
||||
authenticateInternal(crypto, cancel, executor, callback, mContext.getUserId(),
|
||||
null /* confirmDeviceCredentialCallback */);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -597,7 +616,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("Must supply a callback");
|
||||
}
|
||||
authenticateInternal(null /* crypto */, cancel, executor, callback, mContext.getUserId());
|
||||
authenticateInternal(null /* crypto */, cancel, executor, callback, mContext.getUserId(),
|
||||
null /* confirmDeviceCredentialCallback */);
|
||||
}
|
||||
|
||||
private void cancelAuthentication() {
|
||||
@@ -614,7 +634,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
||||
@NonNull CancellationSignal cancel,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull AuthenticationCallback callback,
|
||||
int userId) {
|
||||
int userId,
|
||||
IBiometricConfirmDeviceCredentialCallback confirmDeviceCredentialCallback) {
|
||||
try {
|
||||
if (cancel.isCanceled()) {
|
||||
Log.w(TAG, "Authentication already canceled");
|
||||
@@ -629,7 +650,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
||||
final long sessionId = crypto != null ? crypto.getOpId() : 0;
|
||||
if (BiometricManager.hasBiometrics(mContext)) {
|
||||
mService.authenticate(mToken, sessionId, userId, mBiometricServiceReceiver,
|
||||
mContext.getOpPackageName(), mBundle);
|
||||
mContext.getOpPackageName(), mBundle, confirmDeviceCredentialCallback);
|
||||
} else {
|
||||
mExecutor.execute(() -> {
|
||||
callback.onAuthenticationError(BiometricPrompt.BIOMETRIC_ERROR_HW_NOT_PRESENT,
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.hardware.biometrics;
|
||||
|
||||
/**
|
||||
* Communication channel between ConfirmDeviceCredential / ConfirmLock* and BiometricService.
|
||||
* @hide
|
||||
*/
|
||||
interface IBiometricConfirmDeviceCredentialCallback {
|
||||
// Invoked when authentication should be canceled.
|
||||
oneway void cancel();
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
package android.hardware.biometrics;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.hardware.biometrics.IBiometricConfirmDeviceCredentialCallback;
|
||||
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
|
||||
import android.hardware.biometrics.IBiometricServiceReceiver;
|
||||
|
||||
@@ -30,8 +31,10 @@ import android.hardware.biometrics.IBiometricServiceReceiver;
|
||||
interface IBiometricService {
|
||||
// Requests authentication. The service choose the appropriate biometric to use, and show
|
||||
// the corresponding BiometricDialog.
|
||||
// TODO(b/123378871): Remove callback when moved.
|
||||
void authenticate(IBinder token, long sessionId, int userId,
|
||||
IBiometricServiceReceiver receiver, String opPackageName, in Bundle bundle);
|
||||
IBiometricServiceReceiver receiver, String opPackageName, in Bundle bundle,
|
||||
IBiometricConfirmDeviceCredentialCallback callback);
|
||||
|
||||
// Cancel authentication for the given sessionId
|
||||
void cancelAuthentication(IBinder token, String opPackageName);
|
||||
@@ -59,4 +62,8 @@ interface IBiometricService {
|
||||
void onConfirmDeviceCredentialSuccess();
|
||||
// TODO(b/123378871): Remove when moved.
|
||||
void onConfirmDeviceCredentialError(int error, String message);
|
||||
// TODO(b/123378871): Remove when moved.
|
||||
// When ConfirmLock* is invoked from BiometricPrompt, it needs to register a callback so that
|
||||
// it can receive the cancellation signal.
|
||||
void registerCancellationCallback(IBiometricConfirmDeviceCredentialCallback callback);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import android.hardware.biometrics.BiometricConstants;
|
||||
import android.hardware.biometrics.BiometricPrompt;
|
||||
import android.hardware.biometrics.BiometricSourceType;
|
||||
import android.hardware.biometrics.BiometricsProtoEnums;
|
||||
import android.hardware.biometrics.IBiometricConfirmDeviceCredentialCallback;
|
||||
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
|
||||
import android.hardware.biometrics.IBiometricService;
|
||||
import android.hardware.biometrics.IBiometricServiceReceiver;
|
||||
@@ -85,6 +86,7 @@ import java.util.Random;
|
||||
public class BiometricService extends SystemService {
|
||||
|
||||
private static final String TAG = "BiometricService";
|
||||
private static final boolean DEBUG = true;
|
||||
|
||||
private static final int MSG_ON_TASK_STACK_CHANGED = 1;
|
||||
private static final int MSG_ON_AUTHENTICATION_SUCCEEDED = 2;
|
||||
@@ -96,6 +98,9 @@ public class BiometricService extends SystemService {
|
||||
private static final int MSG_ON_READY_FOR_AUTHENTICATION = 8;
|
||||
private static final int MSG_AUTHENTICATE = 9;
|
||||
private static final int MSG_CANCEL_AUTHENTICATION = 10;
|
||||
private static final int MSG_ON_CONFIRM_DEVICE_CREDENTIAL_SUCCESS = 11;
|
||||
private static final int MSG_ON_CONFIRM_DEVICE_CREDENTIAL_ERROR = 12;
|
||||
private static final int MSG_REGISTER_CANCELLATION_CALLBACK = 13;
|
||||
|
||||
private static final int[] FEATURE_ID = {
|
||||
TYPE_FINGERPRINT,
|
||||
@@ -128,8 +133,12 @@ public class BiometricService extends SystemService {
|
||||
* Authentication is successful, but we're waiting for the user to press "confirm" button.
|
||||
*/
|
||||
private static final int STATE_AUTH_PENDING_CONFIRM = 5;
|
||||
/**
|
||||
* Biometric authentication was canceled, but the device is now showing ConfirmDeviceCredential
|
||||
*/
|
||||
private static final int STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC = 6;
|
||||
|
||||
private final class AuthSession {
|
||||
private final class AuthSession implements IBinder.DeathRecipient {
|
||||
// Map of Authenticator/Cookie pairs. We expect to receive the cookies back from
|
||||
// <Biometric>Services before we can start authenticating. Pairs that have been returned
|
||||
// are moved to mModalitiesMatched.
|
||||
@@ -164,10 +173,14 @@ public class BiometricService extends SystemService {
|
||||
// Timestamp when hardware authentication occurred
|
||||
private long mAuthenticatedTimeMs;
|
||||
|
||||
// TODO(b/123378871): Remove when moved.
|
||||
private IBiometricConfirmDeviceCredentialCallback mConfirmDeviceCredentialCallback;
|
||||
|
||||
AuthSession(HashMap<Integer, Integer> modalities, IBinder token, long sessionId,
|
||||
int userId, IBiometricServiceReceiver receiver, String opPackageName,
|
||||
Bundle bundle, int callingUid, int callingPid, int callingUserId,
|
||||
int modality, boolean requireConfirmation) {
|
||||
int modality, boolean requireConfirmation,
|
||||
IBiometricConfirmDeviceCredentialCallback callback) {
|
||||
mModalitiesWaiting = modalities;
|
||||
mToken = token;
|
||||
mSessionId = sessionId;
|
||||
@@ -180,12 +193,25 @@ public class BiometricService extends SystemService {
|
||||
mCallingUserId = callingUserId;
|
||||
mModality = modality;
|
||||
mRequireConfirmation = requireConfirmation;
|
||||
mConfirmDeviceCredentialCallback = callback;
|
||||
|
||||
if (isFromConfirmDeviceCredential()) {
|
||||
try {
|
||||
token.linkToDeath(this, 0 /* flags */);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Unable to link to death", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isCrypto() {
|
||||
return mSessionId != 0;
|
||||
}
|
||||
|
||||
boolean isFromConfirmDeviceCredential() {
|
||||
return mBundle.getBoolean(BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, false);
|
||||
}
|
||||
|
||||
boolean containsCookie(int cookie) {
|
||||
if (mModalitiesWaiting != null && mModalitiesWaiting.containsValue(cookie)) {
|
||||
return true;
|
||||
@@ -195,6 +221,25 @@ public class BiometricService extends SystemService {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(b/123378871): Remove when moved.
|
||||
@Override
|
||||
public void binderDied() {
|
||||
mHandler.post(() -> {
|
||||
Slog.e(TAG, "Binder died, killing ConfirmDeviceCredential");
|
||||
if (mConfirmDeviceCredentialCallback == null) {
|
||||
Slog.e(TAG, "Callback is null");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mConfirmDeviceCredentialCallback.cancel();
|
||||
mConfirmDeviceCredentialCallback = null;
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Unable to send cancel", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private final class BiometricTaskStackListener extends TaskStackListener {
|
||||
@@ -234,6 +279,14 @@ public class BiometricService extends SystemService {
|
||||
private AuthSession mCurrentAuthSession;
|
||||
private AuthSession mPendingAuthSession;
|
||||
|
||||
// TODO(b/123378871): Remove when moved.
|
||||
// When BiometricPrompt#setAllowDeviceCredentials is set to true, we need to store the
|
||||
// client (app) receiver. BiometricService internally launches CDCA which invokes
|
||||
// BiometricService to start authentication (normal path). When auth is success/rejected,
|
||||
// CDCA will use an aidl method to poke BiometricService - the result will then be forwarded
|
||||
// to this receiver.
|
||||
private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver;
|
||||
|
||||
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
@@ -311,7 +364,8 @@ public class BiometricService extends SystemService {
|
||||
(Bundle) args.arg5 /* bundle */,
|
||||
args.argi2 /* callingUid */,
|
||||
args.argi3 /* callingPid */,
|
||||
args.argi4 /* callingUserId */);
|
||||
args.argi4 /* callingUserId */,
|
||||
(IBiometricConfirmDeviceCredentialCallback) args.arg6 /* callback */);
|
||||
args.recycle();
|
||||
break;
|
||||
}
|
||||
@@ -325,7 +379,28 @@ public class BiometricService extends SystemService {
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_ON_CONFIRM_DEVICE_CREDENTIAL_SUCCESS: {
|
||||
handleOnConfirmDeviceCredentialSuccess();
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_ON_CONFIRM_DEVICE_CREDENTIAL_ERROR: {
|
||||
SomeArgs args = (SomeArgs) msg.obj;
|
||||
handleOnConfirmDeviceCredentialError(
|
||||
args.argi1 /* error */,
|
||||
(String) args.arg1 /* errorMsg */);
|
||||
args.recycle();
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_REGISTER_CANCELLATION_CALLBACK: {
|
||||
handleRegisterCancellationCallback(
|
||||
(IBiometricConfirmDeviceCredentialCallback) msg.obj /* callback */);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
Slog.e(TAG, "Unknown message: " + msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -533,14 +608,6 @@ public class BiometricService extends SystemService {
|
||||
* cancelAuthentication() can go to the right place.
|
||||
*/
|
||||
private final class BiometricServiceWrapper extends IBiometricService.Stub {
|
||||
// TODO(b/123378871): Remove when moved.
|
||||
// When BiometricPrompt#setAllowDeviceCredentials is set to true, we need to store the
|
||||
// client (app) receiver. BiometricService internally launches CDCA which invokes
|
||||
// BiometricService to start authentication (normal path). When auth is success/rejected,
|
||||
// CDCA will use an aidl method to poke BiometricService - the result will then be forwarded
|
||||
// to this receiver.
|
||||
private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver;
|
||||
|
||||
@Override // Binder call
|
||||
public void onReadyForAuthentication(int cookie, boolean requireConfirmation, int userId) {
|
||||
checkInternalPermission();
|
||||
@@ -554,12 +621,18 @@ public class BiometricService extends SystemService {
|
||||
|
||||
@Override // Binder call
|
||||
public void authenticate(IBinder token, long sessionId, int userId,
|
||||
IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle)
|
||||
IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
|
||||
IBiometricConfirmDeviceCredentialCallback callback)
|
||||
throws RemoteException {
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int callingPid = Binder.getCallingPid();
|
||||
final int callingUserId = UserHandle.getCallingUserId();
|
||||
|
||||
// TODO(b/123378871): Remove when moved.
|
||||
if (callback != null) {
|
||||
checkInternalPermission();
|
||||
}
|
||||
|
||||
// In the BiometricServiceBase, check do the AppOps and foreground check.
|
||||
if (userId == callingUserId) {
|
||||
// Check the USE_BIOMETRIC permission here.
|
||||
@@ -576,6 +649,12 @@ public class BiometricService extends SystemService {
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean isFromConfirmDeviceCredential =
|
||||
bundle.getBoolean(BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, false);
|
||||
if (isFromConfirmDeviceCredential) {
|
||||
checkInternalPermission();
|
||||
}
|
||||
|
||||
// Check the usage of this in system server. Need to remove this check if it becomes
|
||||
// a public API.
|
||||
final boolean useDefaultTitle =
|
||||
@@ -632,6 +711,7 @@ public class BiometricService extends SystemService {
|
||||
args.argi2 = callingUid;
|
||||
args.argi3 = callingPid;
|
||||
args.argi4 = callingUserId;
|
||||
args.arg6 = callback;
|
||||
|
||||
mHandler.obtainMessage(MSG_AUTHENTICATE, args).sendToTarget();
|
||||
}
|
||||
@@ -639,35 +719,30 @@ public class BiometricService extends SystemService {
|
||||
@Override // Binder call
|
||||
public void onConfirmDeviceCredentialSuccess() {
|
||||
checkInternalPermission();
|
||||
mHandler.post(() -> {
|
||||
if (mConfirmDeviceCredentialReceiver == null) {
|
||||
Slog.w(TAG, "onCDCASuccess null!");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded();
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "RemoteException", e);
|
||||
}
|
||||
mConfirmDeviceCredentialReceiver = null;
|
||||
});
|
||||
|
||||
mHandler.sendEmptyMessage(MSG_ON_CONFIRM_DEVICE_CREDENTIAL_SUCCESS);
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void onConfirmDeviceCredentialError(int error, String message) {
|
||||
checkInternalPermission();
|
||||
mHandler.post(() -> {
|
||||
if (mConfirmDeviceCredentialReceiver == null) {
|
||||
Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mConfirmDeviceCredentialReceiver.onError(error, message);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "RemoteException", e);
|
||||
}
|
||||
mConfirmDeviceCredentialReceiver = null;
|
||||
});
|
||||
|
||||
SomeArgs args = SomeArgs.obtain();
|
||||
args.argi1 = error;
|
||||
args.arg1 = message;
|
||||
mHandler.obtainMessage(MSG_ON_CONFIRM_DEVICE_CREDENTIAL_ERROR, args).sendToTarget();
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void registerCancellationCallback(
|
||||
IBiometricConfirmDeviceCredentialCallback callback) {
|
||||
// TODO(b/123378871): Remove when moved.
|
||||
// This callback replaces the one stored in the current session. If the session is null
|
||||
// we can ignore this, since it means ConfirmDeviceCredential was launched by something
|
||||
// else (not BiometricPrompt)
|
||||
checkInternalPermission();
|
||||
|
||||
mHandler.obtainMessage(MSG_REGISTER_CANCELLATION_CALLBACK, callback).sendToTarget();
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
@@ -1104,6 +1179,52 @@ public class BiometricService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleOnConfirmDeviceCredentialSuccess() {
|
||||
if (mConfirmDeviceCredentialReceiver == null) {
|
||||
Slog.w(TAG, "onCDCASuccess null!");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
|
||||
mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded();
|
||||
if (mCurrentAuthSession != null) {
|
||||
mCurrentAuthSession.mState = STATE_AUTH_IDLE;
|
||||
mCurrentAuthSession = null;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "RemoteException", e);
|
||||
}
|
||||
mConfirmDeviceCredentialReceiver = null;
|
||||
}
|
||||
|
||||
private void handleOnConfirmDeviceCredentialError(int error, String message) {
|
||||
if (mConfirmDeviceCredentialReceiver == null) {
|
||||
Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
|
||||
mConfirmDeviceCredentialReceiver.onError(error, message);
|
||||
if (mCurrentAuthSession != null) {
|
||||
mCurrentAuthSession.mState = STATE_AUTH_IDLE;
|
||||
mCurrentAuthSession = null;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "RemoteException", e);
|
||||
}
|
||||
mConfirmDeviceCredentialReceiver = null;
|
||||
}
|
||||
|
||||
private void handleRegisterCancellationCallback(
|
||||
IBiometricConfirmDeviceCredentialCallback callback) {
|
||||
if (mCurrentAuthSession == null) {
|
||||
Slog.d(TAG, "Current auth session null");
|
||||
return;
|
||||
}
|
||||
Slog.d(TAG, "Updating cancel callback");
|
||||
mCurrentAuthSession.mConfirmDeviceCredentialCallback = callback;
|
||||
}
|
||||
|
||||
private void handleOnError(int cookie, int error, String message) {
|
||||
Slog.d(TAG, "Error: " + error + " cookie: " + cookie);
|
||||
// Errors can either be from the current auth session or the pending auth session.
|
||||
@@ -1114,7 +1235,18 @@ public class BiometricService extends SystemService {
|
||||
// of their intended receivers.
|
||||
try {
|
||||
if (mCurrentAuthSession != null && mCurrentAuthSession.containsCookie(cookie)) {
|
||||
if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) {
|
||||
|
||||
if (mCurrentAuthSession.isFromConfirmDeviceCredential()) {
|
||||
// If we were invoked by ConfirmDeviceCredential, do not delete the current
|
||||
// auth session since we still need to respond to cancel signal while
|
||||
if (DEBUG) Slog.d(TAG, "From CDC, transition to CANCELED_SHOWING_CDC state");
|
||||
|
||||
// Send the error to ConfirmDeviceCredential so that it goes to Pin/Pattern/Pass
|
||||
// screen
|
||||
mCurrentAuthSession.mClientReceiver.onError(error, message);
|
||||
mCurrentAuthSession.mState = STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC;
|
||||
mStatusBarService.hideBiometricDialog();
|
||||
} else if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) {
|
||||
mStatusBarService.onBiometricError(message);
|
||||
if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
|
||||
mActivityTaskManager.unregisterTaskStackListener(
|
||||
@@ -1214,9 +1346,16 @@ public class BiometricService extends SystemService {
|
||||
KeyStore.getInstance().addAuthToken(mCurrentAuthSession.mTokenEscrow);
|
||||
mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded();
|
||||
}
|
||||
mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
|
||||
mCurrentAuthSession.mState = STATE_AUTH_IDLE;
|
||||
mCurrentAuthSession = null;
|
||||
|
||||
// Do not clean up yet if we are from ConfirmDeviceCredential. We should be in the
|
||||
// STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC. The session should only be removed when
|
||||
// ConfirmDeviceCredential is confirmed or canceled.
|
||||
// TODO(b/123378871): Remove when moved
|
||||
if (!mCurrentAuthSession.isFromConfirmDeviceCredential()) {
|
||||
mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
|
||||
mCurrentAuthSession.mState = STATE_AUTH_IDLE;
|
||||
mCurrentAuthSession = null;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Remote exception", e);
|
||||
}
|
||||
@@ -1235,7 +1374,8 @@ public class BiometricService extends SystemService {
|
||||
mCurrentAuthSession.mCallingUid,
|
||||
mCurrentAuthSession.mCallingPid,
|
||||
mCurrentAuthSession.mCallingUserId,
|
||||
mCurrentAuthSession.mModality);
|
||||
mCurrentAuthSession.mModality,
|
||||
mCurrentAuthSession.mConfirmDeviceCredentialCallback);
|
||||
}
|
||||
|
||||
private void handleOnReadyForAuthentication(int cookie, boolean requireConfirmation,
|
||||
@@ -1290,7 +1430,8 @@ public class BiometricService extends SystemService {
|
||||
|
||||
private void handleAuthenticate(IBinder token, long sessionId, int userId,
|
||||
IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
|
||||
int callingUid, int callingPid, int callingUserId) {
|
||||
int callingUid, int callingPid, int callingUserId,
|
||||
IBiometricConfirmDeviceCredentialCallback callback) {
|
||||
|
||||
mHandler.post(() -> {
|
||||
final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId);
|
||||
@@ -1328,7 +1469,7 @@ public class BiometricService extends SystemService {
|
||||
// Start preparing for authentication. Authentication starts when
|
||||
// all modalities requested have invoked onReadyForAuthentication.
|
||||
authenticateInternal(token, sessionId, userId, receiver, opPackageName, bundle,
|
||||
callingUid, callingPid, callingUserId, modality);
|
||||
callingUid, callingPid, callingUserId, modality, callback);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1343,7 +1484,8 @@ public class BiometricService extends SystemService {
|
||||
*/
|
||||
private void authenticateInternal(IBinder token, long sessionId, int userId,
|
||||
IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
|
||||
int callingUid, int callingPid, int callingUserId, int modality) {
|
||||
int callingUid, int callingPid, int callingUserId, int modality,
|
||||
IBiometricConfirmDeviceCredentialCallback callback) {
|
||||
try {
|
||||
boolean requireConfirmation = bundle.getBoolean(
|
||||
BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true /* default */);
|
||||
@@ -1363,7 +1505,7 @@ public class BiometricService extends SystemService {
|
||||
authenticators.put(modality, cookie);
|
||||
mPendingAuthSession = new AuthSession(authenticators, token, sessionId, userId,
|
||||
receiver, opPackageName, bundle, callingUid, callingPid, callingUserId,
|
||||
modality, requireConfirmation);
|
||||
modality, requireConfirmation, callback);
|
||||
mPendingAuthSession.mState = STATE_AUTH_CALLED;
|
||||
// No polymorphism :(
|
||||
if ((modality & TYPE_FINGERPRINT) != 0) {
|
||||
@@ -1390,10 +1532,23 @@ public class BiometricService extends SystemService {
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to check the current authenticators state. If we're pending confirm
|
||||
// or idle, we need to dismiss the dialog and send an ERROR_CANCELED to the client,
|
||||
// since we won't be getting an onError from the driver.
|
||||
if (mCurrentAuthSession != null && mCurrentAuthSession.mState != STATE_AUTH_STARTED) {
|
||||
if (mCurrentAuthSession != null
|
||||
&& mCurrentAuthSession.mState == STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC) {
|
||||
if (DEBUG) Slog.d(TAG, "Cancel received while ConfirmDeviceCredential showing");
|
||||
try {
|
||||
mCurrentAuthSession.mConfirmDeviceCredentialCallback.cancel();
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Unable to cancel ConfirmDeviceCredential", e);
|
||||
}
|
||||
|
||||
// TODO(b/123378871): Remove when moved. Piggy back on this for now to clean up.
|
||||
handleOnConfirmDeviceCredentialError(BiometricConstants.BIOMETRIC_ERROR_CANCELED,
|
||||
getContext().getString(R.string.biometric_error_canceled));
|
||||
} else if (mCurrentAuthSession != null
|
||||
&& mCurrentAuthSession.mState != STATE_AUTH_STARTED) {
|
||||
// We need to check the current authenticators state. If we're pending confirm
|
||||
// or idle, we need to dismiss the dialog and send an ERROR_CANCELED to the client,
|
||||
// since we won't be getting an onError from the driver.
|
||||
try {
|
||||
// Send error to client
|
||||
mCurrentAuthSession.mClientReceiver.onError(
|
||||
@@ -1409,11 +1564,22 @@ public class BiometricService extends SystemService {
|
||||
Slog.e(TAG, "Remote exception", e);
|
||||
}
|
||||
} else {
|
||||
cancelInternal(token, opPackageName, true /* fromClient */);
|
||||
boolean fromCDC = false;
|
||||
if (mCurrentAuthSession != null) {
|
||||
fromCDC = mCurrentAuthSession.mBundle.getBoolean(
|
||||
BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, false);
|
||||
}
|
||||
|
||||
if (fromCDC) {
|
||||
if (DEBUG) Slog.d(TAG, "Cancelling from CDC");
|
||||
cancelInternal(token, opPackageName, false /* fromClient */);
|
||||
} else {
|
||||
cancelInternal(token, opPackageName, true /* fromClient */);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void cancelInternal(IBinder token, String opPackageName, boolean fromClient) {
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int callingPid = Binder.getCallingPid();
|
||||
|
||||
Reference in New Issue
Block a user