Merge changes from topic "biometric-prompt-service"
* changes: Add BiometricPromptService Remove common biometric directory
This commit is contained in:
committed by
Android (Google) Code Review
commit
49fa609ba0
@@ -151,6 +151,8 @@ java_library {
|
||||
":libcamera_client_framework_aidl",
|
||||
"core/java/android/hardware/IConsumerIrService.aidl",
|
||||
"core/java/android/hardware/ISerialManager.aidl",
|
||||
"core/java/android/hardware/biometrics/IBiometricPromptService.aidl",
|
||||
"core/java/android/hardware/biometrics/IBiometricPromptServiceReceiver.aidl",
|
||||
"core/java/android/hardware/biometrics/IBiometricPromptReceiver.aidl",
|
||||
"core/java/android/hardware/biometrics/IBiometricServiceLockoutResetCallback.aidl",
|
||||
"core/java/android/hardware/display/IDisplayManager.aidl",
|
||||
|
||||
@@ -3671,6 +3671,15 @@ public abstract class Context {
|
||||
*/
|
||||
public static final String AUDIO_SERVICE = "audio";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService(String)}
|
||||
*
|
||||
* @hide
|
||||
* @see #getSystemService(String)
|
||||
* @see com.android.server.biometrics.BiometricPromptService
|
||||
*/
|
||||
public static final String BIOMETRIC_PROMPT_SERVICE = "biometric_prompt";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService(String)} to retrieve a
|
||||
* {@link android.hardware.fingerprint.FingerprintManager} for handling management
|
||||
|
||||
@@ -2279,6 +2279,14 @@ public abstract class PackageManager {
|
||||
@SdkConstant(SdkConstantType.FEATURE)
|
||||
public static final String FEATURE_FACE = "android.hardware.face";
|
||||
|
||||
/**
|
||||
* Feature for {@link #getSystemAvailableFeatures} and
|
||||
* {@link #hasSystemFeature}: The device has biometric hardware to perform iris authentication.
|
||||
* @hide
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.FEATURE)
|
||||
public static final String FEATURE_IRIS = "android.hardware.iris";
|
||||
|
||||
/**
|
||||
* Feature for {@link #getSystemAvailableFeatures} and
|
||||
* {@link #hasSystemFeature}: The device supports portrait orientation
|
||||
|
||||
@@ -160,12 +160,6 @@ public interface BiometricAuthenticator {
|
||||
*/
|
||||
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {}
|
||||
|
||||
/**
|
||||
* Called when a biometric is recognized.
|
||||
* @param result An object containing authentication-related data
|
||||
*/
|
||||
public void onAuthenticationSucceeded(AuthenticationResult result) {}
|
||||
|
||||
/**
|
||||
* Called when a biometric is valid but not recognized.
|
||||
*/
|
||||
@@ -178,6 +172,29 @@ public interface BiometricAuthenticator {
|
||||
public void onAuthenticationAcquired(int acquireInfo) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return true if the biometric hardware is detected.
|
||||
*/
|
||||
default boolean isHardwareDetected() {
|
||||
throw new UnsupportedOperationException("Stub!");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the user has enrolled templates for this biometric.
|
||||
*/
|
||||
default boolean hasEnrolledTemplates() {
|
||||
throw new UnsupportedOperationException("Stub!");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param error
|
||||
* @param vendorCode
|
||||
* @return the error string associated with this error
|
||||
*/
|
||||
default String getErrorString(int error, int vendorCode) {
|
||||
throw new UnsupportedOperationException("Stub!");
|
||||
}
|
||||
|
||||
/**
|
||||
* This call warms up the hardware and starts scanning for valid biometrics. It terminates
|
||||
* when {@link AuthenticationCallback#onAuthenticationError(int,
|
||||
@@ -198,10 +215,12 @@ public interface BiometricAuthenticator {
|
||||
* @param executor An executor to handle callback events
|
||||
* @param callback An object to receive authentication events
|
||||
*/
|
||||
void authenticate(@NonNull CryptoObject crypto,
|
||||
default void authenticate(@NonNull CryptoObject crypto,
|
||||
@NonNull CancellationSignal cancel,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull AuthenticationCallback callback);
|
||||
@NonNull AuthenticationCallback callback) {
|
||||
throw new UnsupportedOperationException("Stub!");
|
||||
}
|
||||
|
||||
/**
|
||||
* This call warms up the hardware and starts scanning for valid biometrics. It terminates
|
||||
@@ -221,7 +240,9 @@ public interface BiometricAuthenticator {
|
||||
* @param executor An executor to handle callback events
|
||||
* @param callback An object to receive authentication events
|
||||
*/
|
||||
void authenticate(@NonNull CancellationSignal cancel,
|
||||
default void authenticate(@NonNull CancellationSignal cancel,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull AuthenticationCallback callback);
|
||||
@NonNull AuthenticationCallback callback) {
|
||||
throw new UnsupportedOperationException("Stub!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,5 +175,5 @@ public interface BiometricConstants {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
int BIOMETRICT_ACQUIRED_VENDOR_BASE = 1000;
|
||||
int BIOMETRIC_ACQUIRED_VENDOR_BASE = 1000;
|
||||
}
|
||||
|
||||
@@ -229,7 +229,8 @@ public interface BiometricFaceConstants {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final int FACE_ACQUIRED_VENDOR = 13;
|
||||
public static final int FACE_ACQUIRED_VENDOR = 14;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
|
||||
@@ -20,14 +20,20 @@ import static android.Manifest.permission.USE_BIOMETRIC;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import java.security.Signature;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -40,6 +46,8 @@ import javax.crypto.Mac;
|
||||
*/
|
||||
public class BiometricPrompt implements BiometricAuthenticator, BiometricConstants {
|
||||
|
||||
private static final String TAG = "BiometricPrompt";
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -208,11 +216,23 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
||||
}
|
||||
}
|
||||
|
||||
private PackageManager mPackageManager;
|
||||
private FingerprintManager mFingerprintManager;
|
||||
private Bundle mBundle;
|
||||
private ButtonInfo mPositiveButtonInfo;
|
||||
private ButtonInfo mNegativeButtonInfo;
|
||||
private class OnAuthenticationCancelListener implements CancellationSignal.OnCancelListener {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
cancelAuthentication();
|
||||
}
|
||||
}
|
||||
|
||||
private final IBinder mToken = new Binder();
|
||||
private final Context mContext;
|
||||
private final IBiometricPromptService mService;
|
||||
private final Bundle mBundle;
|
||||
private final ButtonInfo mPositiveButtonInfo;
|
||||
private final ButtonInfo mNegativeButtonInfo;
|
||||
|
||||
private CryptoObject mCryptoObject;
|
||||
private Executor mExecutor;
|
||||
private AuthenticationCallback mAuthenticationCallback;
|
||||
|
||||
IBiometricPromptReceiver mDialogReceiver = new IBiometricPromptReceiver.Stub() {
|
||||
@Override
|
||||
@@ -230,13 +250,48 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
||||
}
|
||||
};
|
||||
|
||||
IBiometricPromptServiceReceiver mBiometricPromptServiceReceiver =
|
||||
new IBiometricPromptServiceReceiver.Stub() {
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(long deviceId) throws RemoteException {
|
||||
mExecutor.execute(() -> {
|
||||
final AuthenticationResult result = new AuthenticationResult(mCryptoObject);
|
||||
mAuthenticationCallback.onAuthenticationSucceeded(result);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed(long deviceId) throws RemoteException {
|
||||
mExecutor.execute(() -> {
|
||||
mAuthenticationCallback.onAuthenticationFailed();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(long deviceId, int error, String message)
|
||||
throws RemoteException {
|
||||
mExecutor.execute(() -> {
|
||||
mAuthenticationCallback.onAuthenticationError(error, message);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAcquired(long deviceId, int acquireInfo, String message) {
|
||||
mExecutor.execute(() -> {
|
||||
mAuthenticationCallback.onAuthenticationHelp(acquireInfo, message);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private BiometricPrompt(Context context, Bundle bundle,
|
||||
ButtonInfo positiveButtonInfo, ButtonInfo negativeButtonInfo) {
|
||||
mContext = context;
|
||||
mBundle = bundle;
|
||||
mPositiveButtonInfo = positiveButtonInfo;
|
||||
mNegativeButtonInfo = negativeButtonInfo;
|
||||
mFingerprintManager = context.getSystemService(FingerprintManager.class);
|
||||
mPackageManager = context.getPackageManager();
|
||||
mService = IBiometricPromptService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.BIOMETRIC_PROMPT_SERVICE));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -290,13 +345,12 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
||||
/**
|
||||
* Authentication result
|
||||
* @param crypto
|
||||
* @param identifier
|
||||
* @param userId
|
||||
* @hide
|
||||
*/
|
||||
public AuthenticationResult(CryptoObject crypto, Identifier identifier,
|
||||
int userId) {
|
||||
super(crypto, identifier, userId);
|
||||
public AuthenticationResult(CryptoObject crypto) {
|
||||
// For compatibility, this extends from common base class as FingerprintManager does.
|
||||
// Identifier and userId is not used for BiometricPrompt.
|
||||
super(crypto, null /* identifier */, 0 /* userId */);
|
||||
}
|
||||
/**
|
||||
* Obtain the crypto object associated with this transaction
|
||||
@@ -353,53 +407,6 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
||||
*/
|
||||
@Override
|
||||
public void onAuthenticationAcquired(int acquireInfo) {}
|
||||
|
||||
/**
|
||||
* @param result An object containing authentication-related data
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(BiometricAuthenticator.AuthenticationResult result) {
|
||||
onAuthenticationSucceeded(new AuthenticationResult(
|
||||
(CryptoObject) result.getCryptoObject(),
|
||||
result.getId(),
|
||||
result.getUserId()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param crypto Object associated with the call
|
||||
* @param cancel An object that can be used to cancel authentication
|
||||
* @param executor An executor to handle callback events
|
||||
* @param callback An object to receive authentication events
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public void authenticate(@NonNull android.hardware.biometrics.CryptoObject crypto,
|
||||
@NonNull CancellationSignal cancel,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
|
||||
if (!(callback instanceof BiometricPrompt.AuthenticationCallback)) {
|
||||
throw new IllegalArgumentException("Callback cannot be casted");
|
||||
}
|
||||
authenticate(crypto, cancel, executor, (AuthenticationCallback) callback);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param cancel An object that can be used to cancel authentication
|
||||
* @param executor An executor to handle callback events
|
||||
* @param callback An object to receive authentication events
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public void authenticate(@NonNull CancellationSignal cancel,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
|
||||
if (!(callback instanceof BiometricPrompt.AuthenticationCallback)) {
|
||||
throw new IllegalArgumentException("Callback cannot be casted");
|
||||
}
|
||||
authenticate(cancel, executor, (AuthenticationCallback) callback);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -430,11 +437,19 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
||||
@NonNull CancellationSignal cancel,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull AuthenticationCallback callback) {
|
||||
if (handlePreAuthenticationErrors(callback, executor)) {
|
||||
return;
|
||||
if (crypto == null) {
|
||||
throw new IllegalArgumentException("Must supply a crypto object");
|
||||
}
|
||||
mFingerprintManager.authenticate(crypto, cancel, mBundle, executor, mDialogReceiver,
|
||||
callback);
|
||||
if (cancel == null) {
|
||||
throw new IllegalArgumentException("Must supply a cancellation signal");
|
||||
}
|
||||
if (executor == null) {
|
||||
throw new IllegalArgumentException("Must supply an executor");
|
||||
}
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("Must supply a callback");
|
||||
}
|
||||
authenticateInternal(crypto, cancel, executor, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -462,34 +477,53 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
||||
public void authenticate(@NonNull CancellationSignal cancel,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull AuthenticationCallback callback) {
|
||||
if (handlePreAuthenticationErrors(callback, executor)) {
|
||||
return;
|
||||
if (cancel == null) {
|
||||
throw new IllegalArgumentException("Must supply a cancellation signal");
|
||||
}
|
||||
mFingerprintManager.authenticate(cancel, mBundle, executor, mDialogReceiver, callback);
|
||||
if (executor == null) {
|
||||
throw new IllegalArgumentException("Must supply an executor");
|
||||
}
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("Must supply a callback");
|
||||
}
|
||||
authenticateInternal(null /* crypto */, cancel, executor, callback);
|
||||
}
|
||||
|
||||
private boolean handlePreAuthenticationErrors(AuthenticationCallback callback,
|
||||
Executor executor) {
|
||||
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
|
||||
sendError(BiometricPrompt.BIOMETRIC_ERROR_HW_NOT_PRESENT, callback,
|
||||
executor);
|
||||
return true;
|
||||
} else if (!mFingerprintManager.isHardwareDetected()) {
|
||||
sendError(BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE, callback,
|
||||
executor);
|
||||
return true;
|
||||
} else if (!mFingerprintManager.hasEnrolledFingerprints()) {
|
||||
sendError(BiometricPrompt.BIOMETRIC_ERROR_NO_BIOMETRICS, callback,
|
||||
executor);
|
||||
return true;
|
||||
private void cancelAuthentication() {
|
||||
if (mService != null) {
|
||||
try {
|
||||
mService.cancelAuthentication(mToken, mContext.getOpPackageName());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Unable to cancel authentication", e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void sendError(int error, AuthenticationCallback callback, Executor executor) {
|
||||
executor.execute(() -> {
|
||||
callback.onAuthenticationError(error, mFingerprintManager.getErrorString(
|
||||
error, 0 /* vendorCode */));
|
||||
});
|
||||
private void authenticateInternal(@Nullable CryptoObject crypto,
|
||||
@NonNull CancellationSignal cancel,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull AuthenticationCallback callback) {
|
||||
try {
|
||||
if (cancel.isCanceled()) {
|
||||
Log.w(TAG, "Authentication already canceled");
|
||||
return;
|
||||
} else {
|
||||
cancel.setOnCancelListener(new OnAuthenticationCancelListener());
|
||||
}
|
||||
|
||||
mCryptoObject = crypto;
|
||||
mExecutor = executor;
|
||||
mAuthenticationCallback = callback;
|
||||
final long sessionId = crypto != null ? crypto.getOpId() : 0;
|
||||
mService.authenticate(mToken, sessionId, mContext.getUserId(),
|
||||
mBiometricPromptServiceReceiver, 0 /* flags */, mContext.getOpPackageName(),
|
||||
mBundle, mDialogReceiver);
|
||||
} 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));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.hardware.biometrics.IBiometricPromptReceiver;
|
||||
import android.hardware.biometrics.IBiometricPromptServiceReceiver;
|
||||
|
||||
/**
|
||||
* Communication channel from BiometricPrompt to BiometricPromptService. The interface does not
|
||||
* expose specific biometric modalities. The system will use the default biometric for apps. On
|
||||
* devices with more than one, the choice is dictated by user preference in Settings.
|
||||
* @hide
|
||||
*/
|
||||
interface IBiometricPromptService {
|
||||
// Requests authentication. The service choose the appropriate biometric to use, and show
|
||||
// the corresponding BiometricDialog.
|
||||
void authenticate(IBinder token, long sessionId, int userId,
|
||||
IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
|
||||
in Bundle bundle, IBiometricPromptReceiver dialogReceiver);
|
||||
|
||||
// Cancel authentication for the given sessionId
|
||||
void cancelAuthentication(IBinder token, String opPackageName);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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;
|
||||
|
||||
import android.hardware.biometrics.BiometricSourceType;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
|
||||
/**
|
||||
* Communication channel from the BiometricPromptService back to BiometricPrompt.
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IBiometricPromptServiceReceiver {
|
||||
void onAuthenticationSucceeded(long deviceId);
|
||||
void onAuthenticationFailed(long deviceId);
|
||||
void onError(long deviceId, int error, String message);
|
||||
void onAcquired(long deviceId, int acquiredInfo, String message);
|
||||
}
|
||||
@@ -17,10 +17,9 @@
|
||||
package android.hardware.face;
|
||||
|
||||
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
|
||||
import static android.Manifest.permission.MANAGE_FACE;
|
||||
import static android.Manifest.permission.USE_BIOMETRIC;
|
||||
import static android.Manifest.permission.MANAGE_BIOMETRIC;
|
||||
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
@@ -28,13 +27,11 @@ import android.annotation.SystemService;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.BiometricAuthenticator;
|
||||
import android.hardware.biometrics.BiometricConstants;
|
||||
import android.hardware.biometrics.BiometricFaceConstants;
|
||||
import android.hardware.biometrics.BiometricPrompt;
|
||||
import android.hardware.biometrics.CryptoObject;
|
||||
import android.hardware.biometrics.IBiometricPromptReceiver;
|
||||
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.CancellationSignal.OnCancelListener;
|
||||
import android.os.Handler;
|
||||
@@ -50,15 +47,13 @@ import android.util.Slog;
|
||||
import com.android.internal.R;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* A class that coordinates access to the face authentication hardware.
|
||||
* @hide
|
||||
*/
|
||||
@SystemService(Context.FACE_SERVICE)
|
||||
public class FaceManager implements BiometricFaceConstants {
|
||||
|
||||
public class FaceManager implements BiometricAuthenticator, BiometricFaceConstants {
|
||||
|
||||
private static final String TAG = "FaceManager";
|
||||
private static final boolean DEBUG = true;
|
||||
@@ -72,13 +67,12 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
private IFaceService mService;
|
||||
private final Context mContext;
|
||||
private IBinder mToken = new Binder();
|
||||
private BiometricAuthenticator.AuthenticationCallback mAuthenticationCallback;
|
||||
private AuthenticationCallback mAuthenticationCallback;
|
||||
private EnrollmentCallback mEnrollmentCallback;
|
||||
private RemovalCallback mRemovalCallback;
|
||||
private CryptoObject mCryptoObject;
|
||||
private Face mRemovalFace;
|
||||
private Handler mHandler;
|
||||
private Executor mExecutor;
|
||||
|
||||
private IFaceServiceReceiver mServiceReceiver = new IFaceServiceReceiver.Stub() {
|
||||
|
||||
@@ -147,7 +141,7 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
* @throws IllegalStateException if the crypto primitive is not initialized.
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(USE_BIOMETRIC)
|
||||
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
|
||||
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
|
||||
int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
|
||||
if (callback == null) {
|
||||
@@ -170,7 +164,7 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
mCryptoObject = crypto;
|
||||
long sessionId = crypto != null ? crypto.getOpId() : 0;
|
||||
mService.authenticate(mToken, sessionId, mServiceReceiver, flags,
|
||||
mContext.getOpPackageName(), null /* bundle */, null /* receiver */);
|
||||
mContext.getOpPackageName());
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Remote exception while authenticating: ", e);
|
||||
if (callback != null) {
|
||||
@@ -194,108 +188,6 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method invokes the BiometricPrompt.
|
||||
*/
|
||||
private void authenticateWithPrompt(@Nullable android.hardware.biometrics.CryptoObject crypto,
|
||||
@NonNull CancellationSignal cancel,
|
||||
@NonNull Bundle bundle,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull IBiometricPromptReceiver receiver,
|
||||
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
|
||||
mCryptoObject = crypto;
|
||||
if (cancel.isCanceled()) {
|
||||
Slog.w(TAG, "authentication already canceled");
|
||||
return;
|
||||
} else {
|
||||
cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
|
||||
}
|
||||
|
||||
if (mService != null) {
|
||||
try {
|
||||
mExecutor = executor;
|
||||
mAuthenticationCallback = callback;
|
||||
final long sessionId = crypto != null ? crypto.getOpId() : 0;
|
||||
mService.authenticate(mToken, sessionId, mServiceReceiver,
|
||||
0 /* flags */, mContext.getOpPackageName(), bundle, receiver);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Remote exception while authenticating", e);
|
||||
mExecutor.execute(() -> {
|
||||
callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE,
|
||||
getErrorString(FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method, see {@link BiometricPrompt#authenticate(CancellationSignal, Executor,
|
||||
* BiometricPrompt.AuthenticationCallback)}
|
||||
* @param cancel
|
||||
* @param executor
|
||||
* @param callback
|
||||
* @hide
|
||||
*/
|
||||
public void authenticate(
|
||||
@NonNull CancellationSignal cancel,
|
||||
@NonNull Bundle bundle,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull IBiometricPromptReceiver receiver,
|
||||
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
|
||||
if (cancel == null) {
|
||||
throw new IllegalArgumentException("Must supply a cancellation signal");
|
||||
}
|
||||
if (bundle == null) {
|
||||
throw new IllegalArgumentException("Must supply a bundle");
|
||||
}
|
||||
if (executor == null) {
|
||||
throw new IllegalArgumentException("Must supply an executor");
|
||||
}
|
||||
if (receiver == null) {
|
||||
throw new IllegalArgumentException("Must supply a receiver");
|
||||
}
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("Must supply a calback");
|
||||
}
|
||||
authenticateWithPrompt(null, cancel, bundle, executor, receiver, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method, see {@link BiometricPrompt#authenticate(BiometricPrompt.CryptoObject,
|
||||
* CancellationSignal, Executor, BiometricPrompt.AuthenticationCallback)}
|
||||
* @param crypto
|
||||
* @param cancel
|
||||
* @param executor
|
||||
* @param callback
|
||||
* @hide
|
||||
*/
|
||||
public void authenticate(@NonNull android.hardware.biometrics.CryptoObject crypto,
|
||||
@NonNull CancellationSignal cancel,
|
||||
@NonNull Bundle bundle,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull IBiometricPromptReceiver receiver,
|
||||
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
|
||||
if (crypto == null) {
|
||||
throw new IllegalArgumentException("Must supply a crypto object");
|
||||
}
|
||||
if (cancel == null) {
|
||||
throw new IllegalArgumentException("Must supply a cancellation signal");
|
||||
}
|
||||
if (bundle == null) {
|
||||
throw new IllegalArgumentException("Must supply a bundle");
|
||||
}
|
||||
if (executor == null) {
|
||||
throw new IllegalArgumentException("Must supply an executor");
|
||||
}
|
||||
if (receiver == null) {
|
||||
throw new IllegalArgumentException("Must supply a receiver");
|
||||
}
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("Must supply a callback");
|
||||
}
|
||||
authenticateWithPrompt(crypto, cancel, bundle, executor, receiver, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request face authentication enrollment. This call operates the face authentication hardware
|
||||
* and starts capturing images. Progress will be indicated by callbacks to the
|
||||
@@ -313,7 +205,7 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
* @param callback an object to receive enrollment events
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(MANAGE_FACE)
|
||||
@RequiresPermission(MANAGE_BIOMETRIC)
|
||||
public void enroll(byte[] token, CancellationSignal cancel, int flags,
|
||||
int userId, EnrollmentCallback callback) {
|
||||
if (userId == UserHandle.USER_CURRENT) {
|
||||
@@ -355,7 +247,7 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(MANAGE_FACE)
|
||||
@RequiresPermission(MANAGE_BIOMETRIC)
|
||||
public long preEnroll() {
|
||||
long result = 0;
|
||||
if (mService != null) {
|
||||
@@ -373,7 +265,7 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(MANAGE_FACE)
|
||||
@RequiresPermission(MANAGE_BIOMETRIC)
|
||||
public int postEnroll() {
|
||||
int result = 0;
|
||||
if (mService != null) {
|
||||
@@ -392,7 +284,7 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(MANAGE_FACE)
|
||||
@RequiresPermission(MANAGE_BIOMETRIC)
|
||||
public void setActiveUser(int userId) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
@@ -412,7 +304,7 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
* successfully removed. May be null if no callback is required.
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(MANAGE_FACE)
|
||||
@RequiresPermission(MANAGE_BIOMETRIC)
|
||||
public void remove(Face face, int userId, RemovalCallback callback) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
@@ -435,7 +327,7 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
* @return the current face item
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(USE_BIOMETRIC)
|
||||
@RequiresPermission(MANAGE_BIOMETRIC)
|
||||
public List<Face> getEnrolledFaces(int userId) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
@@ -453,7 +345,7 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
* @return the current face item
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(USE_BIOMETRIC)
|
||||
@RequiresPermission(MANAGE_BIOMETRIC)
|
||||
public List<Face> getEnrolledFaces() {
|
||||
return getEnrolledFaces(UserHandle.myUserId());
|
||||
}
|
||||
@@ -463,8 +355,9 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
*
|
||||
* @return true if a face is enrolled, false otherwise
|
||||
*/
|
||||
@RequiresPermission(USE_BIOMETRIC)
|
||||
public boolean hasEnrolledFaces() {
|
||||
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
|
||||
@Override
|
||||
public boolean hasEnrolledTemplates() {
|
||||
if (mService != null) {
|
||||
try {
|
||||
return mService.hasEnrolledFaces(
|
||||
@@ -480,9 +373,9 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(allOf = {
|
||||
USE_BIOMETRIC,
|
||||
USE_BIOMETRIC_INTERNAL,
|
||||
INTERACT_ACROSS_USERS})
|
||||
public boolean hasEnrolledFaces(int userId) {
|
||||
public boolean hasEnrolledTemplates(int userId) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
return mService.hasEnrolledFaces(userId, mContext.getOpPackageName());
|
||||
@@ -498,7 +391,8 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
*
|
||||
* @return true if hardware is present and functional, false otherwise.
|
||||
*/
|
||||
@RequiresPermission(USE_BIOMETRIC)
|
||||
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
|
||||
@Override
|
||||
public boolean isHardwareDetected() {
|
||||
if (mService != null) {
|
||||
try {
|
||||
@@ -538,6 +432,7 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
* @param token an opaque token returned by password confirmation.
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(MANAGE_BIOMETRIC)
|
||||
public void resetTimeout(byte[] token) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
@@ -553,6 +448,7 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
|
||||
public void addLockoutResetCallback(final LockoutResetCallback callback) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
@@ -617,7 +513,8 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
}
|
||||
}
|
||||
|
||||
private String getErrorString(int errMsg, int vendorCode) {
|
||||
@Override
|
||||
public String getErrorString(int errMsg, int vendorCode) {
|
||||
switch (errMsg) {
|
||||
case FACE_ERROR_HW_UNAVAILABLE:
|
||||
return mContext.getString(
|
||||
@@ -652,7 +549,10 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getAcquiredString(int acquireInfo, int vendorCode) {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public String getAcquiredString(int acquireInfo, int vendorCode) {
|
||||
switch (acquireInfo) {
|
||||
case FACE_ACQUIRED_GOOD:
|
||||
return null;
|
||||
@@ -690,6 +590,37 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used so BiometricPrompt can map the face ones onto existing public constants.
|
||||
* @hide
|
||||
*/
|
||||
public int getMappedAcquiredInfo(int acquireInfo, int vendorCode) {
|
||||
switch (acquireInfo) {
|
||||
case FACE_ACQUIRED_GOOD:
|
||||
return BiometricConstants.BIOMETRIC_ACQUIRED_GOOD;
|
||||
case FACE_ACQUIRED_INSUFFICIENT:
|
||||
case FACE_ACQUIRED_TOO_BRIGHT:
|
||||
case FACE_ACQUIRED_TOO_DARK:
|
||||
return BiometricConstants.BIOMETRIC_ACQUIRED_INSUFFICIENT;
|
||||
case FACE_ACQUIRED_TOO_CLOSE:
|
||||
case FACE_ACQUIRED_TOO_FAR:
|
||||
case FACE_ACQUIRED_TOO_HIGH:
|
||||
case FACE_ACQUIRED_TOO_LOW:
|
||||
case FACE_ACQUIRED_TOO_RIGHT:
|
||||
case FACE_ACQUIRED_TOO_LEFT:
|
||||
return BiometricConstants.BIOMETRIC_ACQUIRED_PARTIAL;
|
||||
case FACE_ACQUIRED_POOR_GAZE:
|
||||
case FACE_ACQUIRED_NOT_DETECTED:
|
||||
case FACE_ACQUIRED_TOO_MUCH_MOTION:
|
||||
case FACE_ACQUIRED_RECALIBRATE:
|
||||
return BiometricConstants.BIOMETRIC_ACQUIRED_INSUFFICIENT;
|
||||
case FACE_ACQUIRED_VENDOR:
|
||||
return BiometricConstants.BIOMETRIC_ACQUIRED_VENDOR_BASE + vendorCode;
|
||||
default:
|
||||
return BiometricConstants.BIOMETRIC_ACQUIRED_GOOD;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Container for callback data from {@link FaceManager#authenticate(CryptoObject,
|
||||
* CancellationSignal, int, AuthenticationCallback, Handler)}.
|
||||
@@ -796,18 +727,6 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
*/
|
||||
public void onAuthenticationAcquired(int acquireInfo) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* @param result
|
||||
*/
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(BiometricAuthenticator.AuthenticationResult result) {
|
||||
onAuthenticationSucceeded(new AuthenticationResult(
|
||||
result.getCryptoObject(),
|
||||
(Face) result.getId(), result.getUserId()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -988,8 +907,8 @@ public class FaceManager implements BiometricFaceConstants {
|
||||
|
||||
private void sendAuthenticatedSucceeded(Face face, int userId) {
|
||||
if (mAuthenticationCallback != null) {
|
||||
final BiometricAuthenticator.AuthenticationResult result =
|
||||
new BiometricAuthenticator.AuthenticationResult(mCryptoObject, face, userId);
|
||||
final AuthenticationResult result =
|
||||
new AuthenticationResult(mCryptoObject, face, userId);
|
||||
mAuthenticationCallback.onAuthenticationSucceeded(result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,23 +17,35 @@ package android.hardware.face;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.hardware.biometrics.IBiometricPromptReceiver;
|
||||
import android.hardware.biometrics.IBiometricPromptServiceReceiver;
|
||||
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
|
||||
import android.hardware.face.IFaceServiceReceiver;
|
||||
import android.hardware.face.Face;
|
||||
|
||||
/**
|
||||
* Communication channel from client to the face service.
|
||||
* Communication channel from client to the face service. These methods are all require the
|
||||
* MANAGE_BIOMETRIC signature permission.
|
||||
* @hide
|
||||
*/
|
||||
interface IFaceService {
|
||||
// Authenticate the given sessionId with a face
|
||||
void authenticate(IBinder token, long sessionId,
|
||||
IFaceServiceReceiver receiver, int flags, String opPackageName,
|
||||
in Bundle bundle, IBiometricPromptReceiver dialogReceiver);
|
||||
IFaceServiceReceiver receiver, int flags, String opPackageName);
|
||||
|
||||
// This method invokes the BiometricDialog. The arguments are almost the same as above,
|
||||
// but should only be called from (BiometricPromptService).
|
||||
void authenticateFromService(IBinder token, long sessionId, int userId,
|
||||
IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
|
||||
in Bundle bundle, IBiometricPromptReceiver dialogReceiver,
|
||||
int callingUid, int callingPid, int callingUserId);
|
||||
|
||||
// Cancel authentication for the given sessionId
|
||||
void cancelAuthentication(IBinder token, String opPackageName);
|
||||
|
||||
// Same as above, with extra arguments.
|
||||
void cancelAuthenticationFromService(IBinder token, String opPackageName,
|
||||
int callingUid, int callingPid, int callingUserId);
|
||||
|
||||
// Start face enrollment
|
||||
void enroll(IBinder token, in byte [] cryptoToken, int userId, IFaceServiceReceiver receiver,
|
||||
int flags, String opPackageName);
|
||||
|
||||
@@ -18,10 +18,10 @@ package android.hardware.fingerprint;
|
||||
|
||||
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
|
||||
import static android.Manifest.permission.MANAGE_FINGERPRINT;
|
||||
import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
|
||||
import static android.Manifest.permission.USE_BIOMETRIC;
|
||||
import static android.Manifest.permission.USE_FINGERPRINT;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresFeature;
|
||||
@@ -34,10 +34,8 @@ import android.content.pm.PackageManager;
|
||||
import android.hardware.biometrics.BiometricAuthenticator;
|
||||
import android.hardware.biometrics.BiometricFingerprintConstants;
|
||||
import android.hardware.biometrics.BiometricPrompt;
|
||||
import android.hardware.biometrics.IBiometricPromptReceiver;
|
||||
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.CancellationSignal.OnCancelListener;
|
||||
import android.os.Handler;
|
||||
@@ -66,7 +64,8 @@ import javax.crypto.Mac;
|
||||
@Deprecated
|
||||
@SystemService(Context.FINGERPRINT_SERVICE)
|
||||
@RequiresFeature(PackageManager.FEATURE_FINGERPRINT)
|
||||
public class FingerprintManager implements BiometricFingerprintConstants {
|
||||
public class FingerprintManager implements BiometricAuthenticator, BiometricFingerprintConstants {
|
||||
|
||||
private static final String TAG = "FingerprintManager";
|
||||
private static final boolean DEBUG = true;
|
||||
private static final int MSG_ENROLL_RESULT = 100;
|
||||
@@ -80,14 +79,13 @@ public class FingerprintManager implements BiometricFingerprintConstants {
|
||||
private IFingerprintService mService;
|
||||
private Context mContext;
|
||||
private IBinder mToken = new Binder();
|
||||
private BiometricAuthenticator.AuthenticationCallback mAuthenticationCallback;
|
||||
private AuthenticationCallback mAuthenticationCallback;
|
||||
private EnrollmentCallback mEnrollmentCallback;
|
||||
private RemovalCallback mRemovalCallback;
|
||||
private EnumerateCallback mEnumerateCallback;
|
||||
private android.hardware.biometrics.CryptoObject mCryptoObject;
|
||||
private CryptoObject mCryptoObject;
|
||||
private Fingerprint mRemovalFingerprint;
|
||||
private Handler mHandler;
|
||||
private Executor mExecutor;
|
||||
|
||||
private class OnEnrollCancelListener implements OnCancelListener {
|
||||
@Override
|
||||
@@ -250,24 +248,12 @@ public class FingerprintManager implements BiometricFingerprintConstants {
|
||||
*/
|
||||
@Override
|
||||
public void onAuthenticationAcquired(int acquireInfo) {}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* @param result
|
||||
*/
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(BiometricAuthenticator.AuthenticationResult result) {
|
||||
onAuthenticationSucceeded(new AuthenticationResult(
|
||||
(CryptoObject) result.getCryptoObject(),
|
||||
(Fingerprint) result.getId(), result.getUserId()));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback structure provided to {@link FingerprintManager#enroll(long, EnrollmentCallback,
|
||||
* CancellationSignal, int). Users of {@link #FingerprintManager()}
|
||||
* must provide an implementation of this to {@link FingerprintManager#enroll(long,
|
||||
* CancellationSignal, int, EnrollmentCallback) for listening to fingerprint events.
|
||||
* Callback structure provided to {@link FingerprintManager#enroll(byte[], CancellationSignal,
|
||||
* int, int, EnrollmentCallback)} must provide an implementation of this for listening to
|
||||
* fingerprint events.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@@ -328,9 +314,9 @@ public class FingerprintManager implements BiometricFingerprintConstants {
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback structure provided to {@link FingerprintManager#enumerate(int). Users of
|
||||
* {@link #FingerprintManager()} may optionally provide an implementation of this to
|
||||
* {@link FingerprintManager#enumerate(int, int, EnumerateCallback)} for listening to
|
||||
* Callback structure provided to {@link FingerprintManager#enumerate(int, EnumerateCallback)}.
|
||||
* Users of{@link #FingerprintManager} may optionally provide an implementation of this to
|
||||
* {@link FingerprintManager#enumerate(int, EnumerateCallback)} for listening to
|
||||
* fingerprint template removal events.
|
||||
*
|
||||
* @hide
|
||||
@@ -433,7 +419,7 @@ public class FingerprintManager implements BiometricFingerprintConstants {
|
||||
mCryptoObject = crypto;
|
||||
long sessionId = crypto != null ? crypto.getOpId() : 0;
|
||||
mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,
|
||||
mContext.getOpPackageName(), null /* bundle */, null /* receiver */);
|
||||
mContext.getOpPackageName());
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Remote exception while authenticating: ", e);
|
||||
if (callback != null) {
|
||||
@@ -445,110 +431,6 @@ public class FingerprintManager implements BiometricFingerprintConstants {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Per-user version. This method invokes the BiometricPrompt.
|
||||
*/
|
||||
private void authenticate(int userId,
|
||||
@Nullable android.hardware.biometrics.CryptoObject crypto,
|
||||
@NonNull CancellationSignal cancel,
|
||||
@NonNull Bundle bundle,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull IBiometricPromptReceiver receiver,
|
||||
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
|
||||
mCryptoObject = crypto;
|
||||
if (cancel.isCanceled()) {
|
||||
Slog.w(TAG, "authentication already canceled");
|
||||
return;
|
||||
} else {
|
||||
cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
|
||||
}
|
||||
|
||||
if (mService != null) {
|
||||
try {
|
||||
mExecutor = executor;
|
||||
mAuthenticationCallback = callback;
|
||||
final long sessionId = crypto != null ? crypto.getOpId() : 0;
|
||||
mService.authenticate(mToken, sessionId, userId, mServiceReceiver,
|
||||
0 /* flags */, mContext.getOpPackageName(), bundle, receiver);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Remote exception while authenticating", e);
|
||||
mExecutor.execute(() -> {
|
||||
callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
|
||||
getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method, see {@link BiometricPrompt#authenticate(CancellationSignal, Executor,
|
||||
* BiometricPrompt.AuthenticationCallback)}
|
||||
* @param cancel
|
||||
* @param executor
|
||||
* @param callback
|
||||
* @hide
|
||||
*/
|
||||
public void authenticate(
|
||||
@NonNull CancellationSignal cancel,
|
||||
@NonNull Bundle bundle,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull IBiometricPromptReceiver receiver,
|
||||
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
|
||||
if (cancel == null) {
|
||||
throw new IllegalArgumentException("Must supply a cancellation signal");
|
||||
}
|
||||
if (bundle == null) {
|
||||
throw new IllegalArgumentException("Must supply a bundle");
|
||||
}
|
||||
if (executor == null) {
|
||||
throw new IllegalArgumentException("Must supply an executor");
|
||||
}
|
||||
if (receiver == null) {
|
||||
throw new IllegalArgumentException("Must supply a receiver");
|
||||
}
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("Must supply a calback");
|
||||
}
|
||||
authenticate(mContext.getUserId(), null, cancel, bundle, executor, receiver, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method, see {@link BiometricPrompt#authenticate(BiometricPrompt.CryptoObject,
|
||||
* CancellationSignal, Executor, BiometricPrompt.AuthenticationCallback)}
|
||||
* @param crypto
|
||||
* @param cancel
|
||||
* @param executor
|
||||
* @param callback
|
||||
* @hide
|
||||
*/
|
||||
public void authenticate(@NonNull android.hardware.biometrics.CryptoObject crypto,
|
||||
@NonNull CancellationSignal cancel,
|
||||
@NonNull Bundle bundle,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull IBiometricPromptReceiver receiver,
|
||||
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
|
||||
if (crypto == null) {
|
||||
throw new IllegalArgumentException("Must supply a crypto object");
|
||||
}
|
||||
if (cancel == null) {
|
||||
throw new IllegalArgumentException("Must supply a cancellation signal");
|
||||
}
|
||||
if (bundle == null) {
|
||||
throw new IllegalArgumentException("Must supply a bundle");
|
||||
}
|
||||
if (executor == null) {
|
||||
throw new IllegalArgumentException("Must supply an executor");
|
||||
}
|
||||
if (receiver == null) {
|
||||
throw new IllegalArgumentException("Must supply a receiver");
|
||||
}
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("Must supply a callback");
|
||||
}
|
||||
authenticate(mContext.getUserId(), crypto, cancel,
|
||||
bundle, executor, receiver, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request fingerprint enrollment. This call warms up the fingerprint hardware
|
||||
* and starts scanning for fingerprints. Progress will be indicated by callbacks to the
|
||||
@@ -742,6 +624,14 @@ public class FingerprintManager implements BiometricFingerprintConstants {
|
||||
return getEnrolledFingerprints(mContext.getUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public boolean hasEnrolledTemplates() {
|
||||
return hasEnrolledFingerprints();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if there is at least one fingerprint enrolled.
|
||||
*
|
||||
@@ -785,6 +675,7 @@ public class FingerprintManager implements BiometricFingerprintConstants {
|
||||
*/
|
||||
@Deprecated
|
||||
@RequiresPermission(USE_FINGERPRINT)
|
||||
@Override
|
||||
public boolean isHardwareDetected() {
|
||||
if (mService != null) {
|
||||
try {
|
||||
@@ -826,6 +717,7 @@ public class FingerprintManager implements BiometricFingerprintConstants {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(RESET_FINGERPRINT_LOCKOUT)
|
||||
public void resetTimeout(byte[] token) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
@@ -954,8 +846,8 @@ public class FingerprintManager implements BiometricFingerprintConstants {
|
||||
|
||||
private void sendAuthenticatedSucceeded(Fingerprint fp, int userId) {
|
||||
if (mAuthenticationCallback != null) {
|
||||
final BiometricAuthenticator.AuthenticationResult result =
|
||||
new BiometricAuthenticator.AuthenticationResult(mCryptoObject, fp, userId);
|
||||
final AuthenticationResult result =
|
||||
new AuthenticationResult(mCryptoObject, fp, userId);
|
||||
mAuthenticationCallback.onAuthenticationSucceeded(result);
|
||||
}
|
||||
}
|
||||
@@ -1042,6 +934,7 @@ public class FingerprintManager implements BiometricFingerprintConstants {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public String getErrorString(int errMsg, int vendorCode) {
|
||||
switch (errMsg) {
|
||||
case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
|
||||
@@ -1127,47 +1020,23 @@ public class FingerprintManager implements BiometricFingerprintConstants {
|
||||
|
||||
@Override // binder call
|
||||
public void onAcquired(long deviceId, int acquireInfo, int vendorCode) {
|
||||
if (mExecutor != null) {
|
||||
mExecutor.execute(() -> {
|
||||
sendAcquiredResult(deviceId, acquireInfo, vendorCode);
|
||||
});
|
||||
} else {
|
||||
mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, vendorCode,
|
||||
deviceId).sendToTarget();
|
||||
}
|
||||
mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, vendorCode,
|
||||
deviceId).sendToTarget();
|
||||
}
|
||||
|
||||
@Override // binder call
|
||||
public void onAuthenticationSucceeded(long deviceId, Fingerprint fp, int userId) {
|
||||
if (mExecutor != null) {
|
||||
mExecutor.execute(() -> {
|
||||
sendAuthenticatedSucceeded(fp, userId);
|
||||
});
|
||||
} else {
|
||||
mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, fp).sendToTarget();
|
||||
}
|
||||
mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, fp).sendToTarget();
|
||||
}
|
||||
|
||||
@Override // binder call
|
||||
public void onAuthenticationFailed(long deviceId) {
|
||||
if (mExecutor != null) {
|
||||
mExecutor.execute(() -> {
|
||||
sendAuthenticatedFailed();
|
||||
});
|
||||
} else {
|
||||
mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();
|
||||
}
|
||||
mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();
|
||||
}
|
||||
|
||||
@Override // binder call
|
||||
public void onError(long deviceId, int error, int vendorCode) {
|
||||
if (mExecutor != null) {
|
||||
mExecutor.execute(() -> {
|
||||
sendErrorResult(deviceId, error, vendorCode);
|
||||
});
|
||||
} else {
|
||||
mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget();
|
||||
}
|
||||
mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget();
|
||||
}
|
||||
|
||||
@Override // binder call
|
||||
|
||||
@@ -17,6 +17,7 @@ package android.hardware.fingerprint;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.hardware.biometrics.IBiometricPromptReceiver;
|
||||
import android.hardware.biometrics.IBiometricPromptServiceReceiver;
|
||||
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
|
||||
import android.hardware.fingerprint.IFingerprintClientActiveCallback;
|
||||
import android.hardware.fingerprint.IFingerprintServiceReceiver;
|
||||
@@ -28,14 +29,29 @@ import java.util.List;
|
||||
* @hide
|
||||
*/
|
||||
interface IFingerprintService {
|
||||
// Authenticate the given sessionId with a fingerprint
|
||||
// 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 sessionId, int userId,
|
||||
IFingerprintServiceReceiver receiver, int flags, String opPackageName,
|
||||
in Bundle bundle, IBiometricPromptReceiver dialogReceiver);
|
||||
IFingerprintServiceReceiver receiver, int flags, String opPackageName);
|
||||
|
||||
// This method invokes the BiometricDialog. The arguments are almost the same as above, except
|
||||
// this is protected by the MANAGE_BIOMETRIC signature permission. This method should only be
|
||||
// called from BiometricPromptService. The additional uid, pid, userId arguments should be
|
||||
// determined by BiometricPromptService.
|
||||
void authenticateFromService(IBinder token, long sessionId, int userId,
|
||||
IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
|
||||
in Bundle bundle, IBiometricPromptReceiver dialogReceiver,
|
||||
int callingUid, int callingPid, int callingUserId);
|
||||
|
||||
// Cancel authentication for the given sessionId
|
||||
void cancelAuthentication(IBinder token, String opPackageName);
|
||||
|
||||
// Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes
|
||||
// an additional uid, pid, userid.
|
||||
void cancelAuthenticationFromService(IBinder token, String opPackageName,
|
||||
int callingUid, int callingPid, int callingUserId);
|
||||
|
||||
// Start fingerprint enrollment
|
||||
void enroll(IBinder token, in byte [] cryptoToken, int groupId, IFingerprintServiceReceiver receiver,
|
||||
int flags, String opPackageName);
|
||||
|
||||
@@ -3748,9 +3748,13 @@
|
||||
<permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- Allows managing (adding, removing) facial templates. Reserved for the system. @hide -->
|
||||
<permission android:name="android.permission.MANAGE_FACE"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
<!-- Allows direct access to the <Biometric>Service interfaces. Reserved for the system. @hide -->
|
||||
<permission android:name="android.permission.MANAGE_BIOMETRIC"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- Allows direct access to the <Biometric>Service authentication methods. Reserved for the system. @hide -->
|
||||
<permission android:name="android.permission.USE_BIOMETRIC_INTERNAL"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- Allows an app to reset face authentication attempt counter. Reserved for the system. @hide -->
|
||||
<permission android:name="android.permission.RESET_FACE_LOCKOUT"
|
||||
|
||||
@@ -1397,6 +1397,9 @@
|
||||
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||
<string name="permdesc_mediaLocation">Allows the app to read locations from your media collection.</string>
|
||||
|
||||
<!-- Message shown when biometric hardware is not available [CHAR LIMIT=50] -->
|
||||
<string name="biometric_error_hw_unavailable">Biometric hardware unavailable</string>
|
||||
|
||||
<!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
|
||||
<string name="fingerprint_acquired_partial">Partial fingerprint detected. Please try again.</string>
|
||||
<!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
|
||||
|
||||
@@ -2392,6 +2392,9 @@
|
||||
<!-- From KeyguardServiceDelegate -->
|
||||
<java-symbol type="string" name="config_keyguardComponent" />
|
||||
|
||||
<!-- Biometric messages -->
|
||||
<java-symbol type="string" name="biometric_error_hw_unavailable" />
|
||||
|
||||
<!-- Fingerprint messages -->
|
||||
<java-symbol type="string" name="fingerprint_error_unable_to_process" />
|
||||
<java-symbol type="string" name="fingerprint_error_hw_not_available" />
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
|
||||
<uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
|
||||
<uses-permission android:name="android.permission.TRUST_LISTENER" />
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC_INTERNAL" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
<uses-permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT" />
|
||||
<uses-permission android:name="android.permission.MANAGE_SLICE_PERMISSIONS" />
|
||||
|
||||
@@ -1597,7 +1597,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
|
||||
public boolean isUnlockWithFacePossible(int userId) {
|
||||
return mFaceAuthenticationManager != null && mFaceAuthenticationManager.isHardwareDetected()
|
||||
&& !isFaceDisabled(userId)
|
||||
&& mFaceAuthenticationManager.hasEnrolledFaces(userId);
|
||||
&& mFaceAuthenticationManager.hasEnrolledTemplates(userId);
|
||||
}
|
||||
|
||||
private void stopListeningForFingerprint() {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.server.biometrics.common;
|
||||
package com.android.server.biometrics;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.BiometricAuthenticator;
|
||||
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.biometrics;
|
||||
|
||||
import static android.Manifest.permission.USE_BIOMETRIC;
|
||||
import static android.Manifest.permission.USE_FINGERPRINT;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.biometrics.BiometricAuthenticator;
|
||||
import android.hardware.biometrics.BiometricConstants;
|
||||
import android.hardware.biometrics.IBiometricPromptReceiver;
|
||||
import android.hardware.biometrics.IBiometricPromptService;
|
||||
import android.hardware.biometrics.IBiometricPromptServiceReceiver;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.face.IFaceService;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.hardware.fingerprint.IFingerprintService;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.os.SomeArgs;
|
||||
import com.android.server.SystemService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* System service that arbitrates the modality for BiometricPrompt to use.
|
||||
*/
|
||||
public class BiometricPromptService extends SystemService {
|
||||
|
||||
private static final String TAG = "BiometricPromptService";
|
||||
|
||||
/**
|
||||
* No biometric methods or nothing has been enrolled.
|
||||
* Move/expose these in BiometricPrompt if we ever want to allow applications to "blacklist"
|
||||
* modalities when calling authenticate().
|
||||
*/
|
||||
private static final int BIOMETRIC_NONE = 0;
|
||||
|
||||
/**
|
||||
* Constant representing fingerprint.
|
||||
*/
|
||||
private static final int BIOMETRIC_FINGERPRINT = 1 << 0;
|
||||
|
||||
/**
|
||||
* Constant representing iris.
|
||||
*/
|
||||
private static final int BIOMETRIC_IRIS = 1 << 1;
|
||||
|
||||
/**
|
||||
* Constant representing face.
|
||||
*/
|
||||
private static final int BIOMETRIC_FACE = 1 << 2;
|
||||
|
||||
private static final int[] FEATURE_ID = {
|
||||
BIOMETRIC_FINGERPRINT,
|
||||
BIOMETRIC_IRIS,
|
||||
BIOMETRIC_FACE
|
||||
};
|
||||
|
||||
private final Handler mHandler;
|
||||
private final boolean mHasFeatureFingerprint;
|
||||
private final boolean mHasFeatureIris;
|
||||
private final boolean mHasFeatureFace;
|
||||
|
||||
private IFingerprintService mFingerprintService;
|
||||
private IFaceService mFaceService;
|
||||
|
||||
// Get and cache the available authenticator (manager) classes. Used since aidl doesn't support
|
||||
// polymorphism :/
|
||||
final ArrayList<Authenticator> mAuthenticators = new ArrayList<>();
|
||||
|
||||
// Cache the current service that's being used. This is the service which
|
||||
// cancelAuthentication() must be forwarded to. This is just a cache, and the actual
|
||||
// check (is caller the current client) is done in the <Biometric>Service.
|
||||
// Since Settings/System (not application) is responsible for changing preference, this
|
||||
// should be safe.
|
||||
private int mCurrentModality;
|
||||
|
||||
private final class Authenticator {
|
||||
int mType;
|
||||
BiometricAuthenticator mAuthenticator;
|
||||
|
||||
Authenticator(int type, BiometricAuthenticator authenticator) {
|
||||
mType = type;
|
||||
mAuthenticator = authenticator;
|
||||
}
|
||||
|
||||
int getType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
BiometricAuthenticator getAuthenticator() {
|
||||
return mAuthenticator;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is just a pass-through service that wraps Fingerprint, Iris, Face services. This service
|
||||
* should not carry any state. The reality is we need to keep a tiny amount of state so that
|
||||
* cancelAuthentication() can go to the right place.
|
||||
*/
|
||||
private final class BiometricPromptServiceWrapper extends IBiometricPromptService.Stub {
|
||||
|
||||
@Override // Binder call
|
||||
public void authenticate(IBinder token, long sessionId, int userId,
|
||||
IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
|
||||
Bundle bundle, IBiometricPromptReceiver dialogReceiver) throws RemoteException {
|
||||
// Check the USE_BIOMETRIC permission here. In the BiometricService, check do the
|
||||
// AppOps and foreground check.
|
||||
checkPermission();
|
||||
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int callingPid = Binder.getCallingPid();
|
||||
final int callingUserId = UserHandle.getCallingUserId();
|
||||
|
||||
mHandler.post(() -> {
|
||||
mCurrentModality = checkAndGetBiometricModality(receiver);
|
||||
|
||||
try {
|
||||
// No polymorphism :(
|
||||
if (mCurrentModality == BIOMETRIC_FINGERPRINT) {
|
||||
mFingerprintService.authenticateFromService(token, sessionId, userId,
|
||||
receiver, flags, opPackageName, bundle, dialogReceiver,
|
||||
callingUid, callingPid, callingUserId);
|
||||
} else if (mCurrentModality == BIOMETRIC_IRIS) {
|
||||
Slog.w(TAG, "Unsupported modality");
|
||||
} else if (mCurrentModality == BIOMETRIC_FACE) {
|
||||
mFaceService.authenticateFromService(token, sessionId, userId,
|
||||
receiver, flags, opPackageName, bundle, dialogReceiver,
|
||||
callingUid, callingPid, callingUserId);
|
||||
} else {
|
||||
Slog.w(TAG, "Unsupported modality");
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Unable to start authentication", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void cancelAuthentication(IBinder token, String opPackageName)
|
||||
throws RemoteException {
|
||||
checkPermission();
|
||||
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int callingPid = Binder.getCallingPid();
|
||||
final int callingUserId = UserHandle.getCallingUserId();
|
||||
|
||||
mHandler.post(() -> {
|
||||
try {
|
||||
if (mCurrentModality == BIOMETRIC_FINGERPRINT) {
|
||||
mFingerprintService.cancelAuthenticationFromService(token, opPackageName,
|
||||
callingUid, callingPid, callingUserId);
|
||||
} else if (mCurrentModality == BIOMETRIC_IRIS) {
|
||||
Slog.w(TAG, "Unsupported modality");
|
||||
} else if (mCurrentModality == BIOMETRIC_FACE) {
|
||||
mFaceService.cancelAuthenticationFromService(token, opPackageName,
|
||||
callingUid, callingPid, callingUserId);
|
||||
} else {
|
||||
Slog.w(TAG, "Unsupported modality");
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Unable to cancel authentication");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPermission() {
|
||||
if (getContext().checkCallingPermission(USE_FINGERPRINT)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
getContext().enforceCallingPermission(USE_BIOMETRIC,
|
||||
"Must have USE_BIOMETRIC permission");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the system service.
|
||||
* <p>
|
||||
* Subclasses must define a single argument constructor that accepts the context
|
||||
* and passes it to super.
|
||||
* </p>
|
||||
*
|
||||
* @param context The system server context.
|
||||
*/
|
||||
public BiometricPromptService(Context context) {
|
||||
super(context);
|
||||
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
mHasFeatureFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
|
||||
mHasFeatureIris = pm.hasSystemFeature(PackageManager.FEATURE_IRIS);
|
||||
mHasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
// TODO: maybe get these on-demand
|
||||
if (mHasFeatureFingerprint) {
|
||||
mFingerprintService = IFingerprintService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.FINGERPRINT_SERVICE));
|
||||
}
|
||||
if (mHasFeatureFace) {
|
||||
mFaceService = IFaceService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.FACE_SERVICE));
|
||||
}
|
||||
|
||||
// Cache the authenticators
|
||||
for (int i = 0; i < FEATURE_ID.length; i++) {
|
||||
if (hasFeature(FEATURE_ID[i])) {
|
||||
Authenticator authenticator =
|
||||
new Authenticator(FEATURE_ID[i], getAuthenticator(FEATURE_ID[i]));
|
||||
mAuthenticators.add(authenticator);
|
||||
}
|
||||
}
|
||||
|
||||
publishBinderService(Context.BIOMETRIC_PROMPT_SERVICE, new BiometricPromptServiceWrapper());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there are any available biometrics, and returns the modality. This method also
|
||||
* returns errors through the callback (no biometric feature, hardware not detected, no
|
||||
* templates enrolled, etc). This service must not start authentication if errors are sent.
|
||||
*/
|
||||
private int checkAndGetBiometricModality(IBiometricPromptServiceReceiver receiver) {
|
||||
int modality = BIOMETRIC_NONE;
|
||||
final String hardwareUnavailable =
|
||||
getContext().getString(R.string.biometric_error_hw_unavailable);
|
||||
|
||||
// No biometric features, send error
|
||||
if (mAuthenticators.isEmpty()) {
|
||||
try {
|
||||
receiver.onError(0 /* deviceId */,
|
||||
BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT,
|
||||
hardwareUnavailable);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Unable to send error", e);
|
||||
}
|
||||
return BIOMETRIC_NONE;
|
||||
}
|
||||
|
||||
// Find first authenticator that's both detected and enrolled
|
||||
boolean isHardwareDetected = false;
|
||||
boolean hasTemplatesEnrolled = false;
|
||||
for (int i = 0; i < mAuthenticators.size(); i++) {
|
||||
int featureId = mAuthenticators.get(i).getType();
|
||||
BiometricAuthenticator authenticator = mAuthenticators.get(i).getAuthenticator();
|
||||
if (authenticator.isHardwareDetected()) {
|
||||
isHardwareDetected = true;
|
||||
if (authenticator.hasEnrolledTemplates()) {
|
||||
hasTemplatesEnrolled = true;
|
||||
modality = featureId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check error conditions
|
||||
if (!isHardwareDetected) {
|
||||
try {
|
||||
receiver.onError(0 /* deviceId */,
|
||||
BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
|
||||
hardwareUnavailable);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Unable to send error", e);
|
||||
}
|
||||
return BIOMETRIC_NONE;
|
||||
}
|
||||
if (!hasTemplatesEnrolled) {
|
||||
try {
|
||||
receiver.onError(0 /* deviceId */,
|
||||
BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS,
|
||||
hardwareUnavailable);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Unable to send error", e);
|
||||
}
|
||||
return BIOMETRIC_NONE;
|
||||
}
|
||||
|
||||
return modality;
|
||||
}
|
||||
|
||||
private BiometricAuthenticator getAuthenticator(int type) {
|
||||
switch (type) {
|
||||
case BIOMETRIC_FINGERPRINT:
|
||||
return (FingerprintManager)
|
||||
getContext().getSystemService(Context.FINGERPRINT_SERVICE);
|
||||
case BIOMETRIC_IRIS:
|
||||
return null;
|
||||
case BIOMETRIC_FACE:
|
||||
return (FaceManager)
|
||||
getContext().getSystemService(Context.FACE_SERVICE);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasFeature(int type) {
|
||||
switch (type) {
|
||||
case BIOMETRIC_FINGERPRINT:
|
||||
return mHasFeatureFingerprint;
|
||||
case BIOMETRIC_IRIS:
|
||||
return mHasFeatureIris;
|
||||
case BIOMETRIC_FACE:
|
||||
return mHasFeatureFace;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,10 @@
|
||||
* 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.
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.server.biometrics.common;
|
||||
package com.android.server.biometrics;
|
||||
|
||||
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
|
||||
|
||||
@@ -333,8 +333,8 @@ public abstract class BiometricService extends SystemService implements IHwBinde
|
||||
* Wraps the callback interface from Service -> Manager
|
||||
*/
|
||||
protected interface ServiceListener {
|
||||
void onEnrollResult(BiometricAuthenticator.Identifier identifier,
|
||||
int remaining) throws RemoteException;
|
||||
default void onEnrollResult(BiometricAuthenticator.Identifier identifier,
|
||||
int remaining) throws RemoteException {};
|
||||
|
||||
void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
|
||||
throws RemoteException;
|
||||
@@ -349,11 +349,11 @@ public abstract class BiometricService extends SystemService implements IHwBinde
|
||||
void onError(long deviceId, int error, int vendorCode)
|
||||
throws RemoteException;
|
||||
|
||||
void onRemoved(BiometricAuthenticator.Identifier identifier,
|
||||
int remaining) throws RemoteException;
|
||||
default void onRemoved(BiometricAuthenticator.Identifier identifier,
|
||||
int remaining) throws RemoteException {};
|
||||
|
||||
void onEnumerated(BiometricAuthenticator.Identifier identifier,
|
||||
int remaining) throws RemoteException;
|
||||
default void onEnumerated(BiometricAuthenticator.Identifier identifier,
|
||||
int remaining) throws RemoteException {};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -688,7 +688,11 @@ public abstract class BiometricService extends SystemService implements IHwBinde
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int callingPid = Binder.getCallingPid();
|
||||
final int callingUserId = UserHandle.getCallingUserId();
|
||||
authenticateInternal(client, opId, opPackageName, callingUid, callingPid, callingUserId);
|
||||
}
|
||||
|
||||
protected void authenticateInternal(AuthenticationClientImpl client, long opId,
|
||||
String opPackageName, int callingUid, int callingPid, int callingUserId) {
|
||||
if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
|
||||
callingUserId)) {
|
||||
if (DEBUG) Slog.v(getTag(), "authenticate(): reject " + opPackageName);
|
||||
@@ -716,7 +720,11 @@ public abstract class BiometricService extends SystemService implements IHwBinde
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int callingPid = Binder.getCallingPid();
|
||||
final int callingUserId = UserHandle.getCallingUserId();
|
||||
cancelAuthenticationInternal(token, opPackageName, callingUid, callingPid, callingUserId);
|
||||
}
|
||||
|
||||
protected void cancelAuthenticationInternal(final IBinder token, final String opPackageName,
|
||||
int callingUid, int callingPid, int callingUserId) {
|
||||
if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
|
||||
callingUserId)) {
|
||||
if (DEBUG) Slog.v(getTag(), "cancelAuthentication(): reject " + opPackageName);
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.server.biometrics.common;
|
||||
package com.android.server.biometrics;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.BiometricAuthenticator;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.server.biometrics.common;
|
||||
package com.android.server.biometrics;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.BiometricAuthenticator;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.server.biometrics.common;
|
||||
package com.android.server.biometrics;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.BiometricAuthenticator;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.server.biometrics.common;
|
||||
package com.android.server.biometrics;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.BiometricAuthenticator;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.server.biometrics.common;
|
||||
package com.android.server.biometrics;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.BiometricAuthenticator;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.server.biometrics.common;
|
||||
package com.android.server.biometrics;
|
||||
|
||||
public interface Metrics {
|
||||
/** The log tag */
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.server.biometrics.common;
|
||||
package com.android.server.biometrics;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.BiometricAuthenticator;
|
||||
@@ -17,7 +17,7 @@
|
||||
package com.android.server.biometrics.face;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.server.biometrics.common.Metrics;
|
||||
import com.android.server.biometrics.Metrics;
|
||||
|
||||
public class FaceMetrics implements Metrics {
|
||||
@Override
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
package com.android.server.biometrics.face;
|
||||
|
||||
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
|
||||
import static android.Manifest.permission.MANAGE_FACE;
|
||||
import static android.Manifest.permission.MANAGE_BIOMETRIC;
|
||||
import static android.Manifest.permission.RESET_FACE_LOCKOUT;
|
||||
import static android.Manifest.permission.USE_BIOMETRIC;
|
||||
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AppOpsManager;
|
||||
@@ -28,10 +28,12 @@ import android.content.pm.UserInfo;
|
||||
import android.hardware.biometrics.BiometricAuthenticator;
|
||||
import android.hardware.biometrics.BiometricConstants;
|
||||
import android.hardware.biometrics.IBiometricPromptReceiver;
|
||||
import android.hardware.biometrics.IBiometricPromptServiceReceiver;
|
||||
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
|
||||
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
|
||||
import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
|
||||
import android.hardware.face.Face;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.face.IFaceService;
|
||||
import android.hardware.face.IFaceServiceReceiver;
|
||||
import android.os.Binder;
|
||||
@@ -51,9 +53,9 @@ import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.server.SystemServerInitThreadPool;
|
||||
import com.android.server.biometrics.common.BiometricService;
|
||||
import com.android.server.biometrics.common.BiometricUtils;
|
||||
import com.android.server.biometrics.common.Metrics;
|
||||
import com.android.server.biometrics.BiometricService;
|
||||
import com.android.server.biometrics.BiometricUtils;
|
||||
import com.android.server.biometrics.Metrics;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
@@ -92,13 +94,13 @@ public class FaceService extends BiometricService {
|
||||
*/
|
||||
@Override // Binder call
|
||||
public long preEnroll(IBinder token) {
|
||||
checkPermission(MANAGE_FACE);
|
||||
checkPermission(MANAGE_BIOMETRIC);
|
||||
return startPreEnroll(token);
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public int postEnroll(IBinder token) {
|
||||
checkPermission(MANAGE_FACE);
|
||||
checkPermission(MANAGE_BIOMETRIC);
|
||||
return startPostEnroll(token);
|
||||
}
|
||||
|
||||
@@ -106,7 +108,7 @@ public class FaceService extends BiometricService {
|
||||
public void enroll(final IBinder token, final byte[] cryptoToken, final int userId,
|
||||
final IFaceServiceReceiver receiver, final int flags,
|
||||
final String opPackageName) {
|
||||
checkPermission(MANAGE_FACE);
|
||||
checkPermission(MANAGE_BIOMETRIC);
|
||||
|
||||
final boolean restricted = isRestricted();
|
||||
final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
|
||||
@@ -118,39 +120,64 @@ public class FaceService extends BiometricService {
|
||||
|
||||
@Override // Binder call
|
||||
public void cancelEnrollment(final IBinder token) {
|
||||
checkPermission(MANAGE_FACE);
|
||||
checkPermission(MANAGE_BIOMETRIC);
|
||||
cancelEnrollmentInternal(token);
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void authenticate(final IBinder token, final long opId,
|
||||
final IFaceServiceReceiver receiver, final int flags,
|
||||
final String opPackageName, final Bundle bundle,
|
||||
final IBiometricPromptReceiver dialogReceiver) {
|
||||
final String opPackageName) {
|
||||
checkPermission(USE_BIOMETRIC_INTERNAL);
|
||||
final boolean restricted = isRestricted();
|
||||
final AuthenticationClientImpl client = new AuthenticationClientImpl(getContext(),
|
||||
mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
|
||||
mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName, bundle,
|
||||
dialogReceiver, mStatusBarService);
|
||||
mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName,
|
||||
null /* bundle */, null /* dialogReceiver */, mStatusBarService);
|
||||
|
||||
authenticateInternal(client, opId, opPackageName);
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void authenticateFromService(IBinder token, long opId, int groupId,
|
||||
IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
|
||||
Bundle bundle, IBiometricPromptReceiver dialogReceiver,
|
||||
int callingUid, int callingPid, int callingUserId) {
|
||||
checkPermission(USE_BIOMETRIC_INTERNAL);
|
||||
final boolean restricted = true; // BiometricPrompt is always restricted
|
||||
final AuthenticationClientImpl client = new AuthenticationClientImpl(getContext(),
|
||||
mDaemonWrapper, mHalDeviceId, token,
|
||||
new BiometricPromptServiceListenerImpl(receiver),
|
||||
mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName,
|
||||
bundle, dialogReceiver, mStatusBarService);
|
||||
authenticateInternal(client, opId, opPackageName, callingUid, callingPid,
|
||||
callingUserId);
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void cancelAuthentication(final IBinder token, final String opPackageName) {
|
||||
checkPermission(USE_BIOMETRIC_INTERNAL);
|
||||
cancelAuthenticationInternal(token, opPackageName);
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void cancelAuthenticationFromService(final IBinder token, final String opPackageName,
|
||||
int callingUid, int callingPid, int callingUserId) {
|
||||
checkPermission(USE_BIOMETRIC_INTERNAL);
|
||||
cancelAuthenticationInternal(token, opPackageName,
|
||||
callingUid, callingPid, callingUserId);
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void setActiveUser(final int userId) {
|
||||
checkPermission(MANAGE_FACE);
|
||||
checkPermission(MANAGE_BIOMETRIC);
|
||||
setActiveUserInternal(userId);
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void remove(final IBinder token, final int faceId, final int userId,
|
||||
final IFaceServiceReceiver receiver) {
|
||||
checkPermission(MANAGE_FACE);
|
||||
checkPermission(MANAGE_BIOMETRIC);
|
||||
|
||||
if (token == null) {
|
||||
Slog.w(TAG, "remove(): token is null");
|
||||
@@ -168,7 +195,7 @@ public class FaceService extends BiometricService {
|
||||
@Override
|
||||
public void enumerate(final IBinder token, final int userId,
|
||||
final IFaceServiceReceiver receiver) {
|
||||
checkPermission(MANAGE_FACE);
|
||||
checkPermission(MANAGE_BIOMETRIC);
|
||||
|
||||
final boolean restricted = isRestricted();
|
||||
final EnumerateClientImpl client = new EnumerateClientImpl(getContext(), mDaemonWrapper,
|
||||
@@ -180,6 +207,7 @@ public class FaceService extends BiometricService {
|
||||
@Override
|
||||
public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback)
|
||||
throws RemoteException {
|
||||
checkPermission(USE_BIOMETRIC_INTERNAL);
|
||||
FaceService.super.addLockoutResetCallback(callback);
|
||||
}
|
||||
|
||||
@@ -208,6 +236,7 @@ public class FaceService extends BiometricService {
|
||||
// TODO: refactor out common code here
|
||||
@Override // Binder call
|
||||
public boolean isHardwareDetected(long deviceId, String opPackageName) {
|
||||
checkPermission(USE_BIOMETRIC_INTERNAL);
|
||||
if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
|
||||
Binder.getCallingUid(), Binder.getCallingPid(),
|
||||
UserHandle.getCallingUserId())) {
|
||||
@@ -225,7 +254,7 @@ public class FaceService extends BiometricService {
|
||||
|
||||
@Override // Binder call
|
||||
public void rename(final int faceId, final String name) {
|
||||
checkPermission(MANAGE_FACE);
|
||||
checkPermission(MANAGE_BIOMETRIC);
|
||||
if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) {
|
||||
return;
|
||||
}
|
||||
@@ -240,6 +269,7 @@ public class FaceService extends BiometricService {
|
||||
|
||||
@Override // Binder call
|
||||
public List<Face> getEnrolledFaces(int userId, String opPackageName) {
|
||||
checkPermission(MANAGE_BIOMETRIC);
|
||||
if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
|
||||
Binder.getCallingUid(), Binder.getCallingPid(),
|
||||
UserHandle.getCallingUserId())) {
|
||||
@@ -251,6 +281,7 @@ public class FaceService extends BiometricService {
|
||||
|
||||
@Override // Binder call
|
||||
public boolean hasEnrolledFaces(int userId, String opPackageName) {
|
||||
checkPermission(USE_BIOMETRIC_INTERNAL);
|
||||
if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
|
||||
Binder.getCallingUid(), Binder.getCallingPid(),
|
||||
UserHandle.getCallingUserId())) {
|
||||
@@ -283,12 +314,64 @@ public class FaceService extends BiometricService {
|
||||
|
||||
@Override // Binder call
|
||||
public void resetTimeout(byte[] token) {
|
||||
checkPermission(RESET_FACE_LOCKOUT);
|
||||
checkPermission(MANAGE_BIOMETRIC);
|
||||
// TODO: confirm security token when we move timeout management into the HAL layer.
|
||||
mHandler.post(mResetFailedAttemptsForCurrentUserRunnable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives callbacks from the ClientMonitor implementations. The results are forwarded to
|
||||
* BiometricPrompt.
|
||||
*/
|
||||
private class BiometricPromptServiceListenerImpl implements ServiceListener {
|
||||
|
||||
// Use FaceManager to get strings, so BiometricPrompt interface is cleaner
|
||||
private FaceManager mFaceManager;
|
||||
private IBiometricPromptServiceReceiver mBiometricPromptServiceReceiver;
|
||||
|
||||
public BiometricPromptServiceListenerImpl(IBiometricPromptServiceReceiver receiver) {
|
||||
mBiometricPromptServiceReceiver = receiver;
|
||||
mFaceManager = (FaceManager) getContext().getSystemService(Context.FACE_SERVICE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
|
||||
throws RemoteException {
|
||||
/**
|
||||
* Map the acquired codes onto existing {@link BiometricConstants} acquired codes.
|
||||
*/
|
||||
if (mBiometricPromptServiceReceiver != null) {
|
||||
mBiometricPromptServiceReceiver.onAcquired(deviceId,
|
||||
mFaceManager.getMappedAcquiredInfo(acquiredInfo, vendorCode),
|
||||
mFaceManager.getAcquiredString(acquiredInfo, vendorCode));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(long deviceId,
|
||||
BiometricAuthenticator.Identifier biometric, int userId) throws RemoteException {
|
||||
if (mBiometricPromptServiceReceiver != null) {
|
||||
mBiometricPromptServiceReceiver.onAuthenticationSucceeded(deviceId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed(long deviceId) throws RemoteException {
|
||||
if (mBiometricPromptServiceReceiver != null) {
|
||||
mBiometricPromptServiceReceiver.onAuthenticationFailed(deviceId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(long deviceId, int error, int vendorCode) throws RemoteException {
|
||||
if (mBiometricPromptServiceReceiver != null) {
|
||||
mBiometricPromptServiceReceiver.onError(deviceId, error,
|
||||
mFaceManager.getErrorString(error, vendorCode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives callbacks from the ClientMonitor implementations. The results are forwarded to
|
||||
* the FaceManager.
|
||||
@@ -616,12 +699,13 @@ public class FaceService extends BiometricService {
|
||||
|
||||
@Override
|
||||
protected String getManageBiometricPermission() {
|
||||
return MANAGE_FACE;
|
||||
return MANAGE_BIOMETRIC;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkUseBiometricPermission() {
|
||||
checkPermission(USE_BIOMETRIC);
|
||||
// noop for Face. The permission checks are all done on the incoming binder call.
|
||||
// TODO: Perhaps do the same in FingerprintService
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,7 +24,7 @@ import android.util.Slog;
|
||||
import android.util.Xml;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.server.biometrics.common.BiometricUserState;
|
||||
import com.android.server.biometrics.BiometricUserState;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import android.text.TextUtils;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.server.biometrics.common.BiometricUtils;
|
||||
import com.android.server.biometrics.BiometricUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package com.android.server.biometrics.fingerprint;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.server.biometrics.common.Metrics;
|
||||
import com.android.server.biometrics.Metrics;
|
||||
|
||||
public class FingerprintMetrics implements Metrics {
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.server.biometrics.fingerprint;
|
||||
|
||||
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
|
||||
import static android.Manifest.permission.MANAGE_BIOMETRIC;
|
||||
import static android.Manifest.permission.MANAGE_FINGERPRINT;
|
||||
import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
|
||||
import static android.Manifest.permission.USE_BIOMETRIC;
|
||||
@@ -30,10 +31,12 @@ import android.content.pm.UserInfo;
|
||||
import android.hardware.biometrics.BiometricAuthenticator;
|
||||
import android.hardware.biometrics.BiometricConstants;
|
||||
import android.hardware.biometrics.IBiometricPromptReceiver;
|
||||
import android.hardware.biometrics.IBiometricPromptServiceReceiver;
|
||||
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
|
||||
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
|
||||
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprintClientCallback;
|
||||
import android.hardware.fingerprint.Fingerprint;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.hardware.fingerprint.IFingerprintClientActiveCallback;
|
||||
import android.hardware.fingerprint.IFingerprintService;
|
||||
import android.hardware.fingerprint.IFingerprintServiceReceiver;
|
||||
@@ -42,7 +45,6 @@ import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SELinux;
|
||||
import android.os.ServiceManager;
|
||||
@@ -56,11 +58,11 @@ import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.server.SystemServerInitThreadPool;
|
||||
import com.android.server.biometrics.common.BiometricService;
|
||||
import com.android.server.biometrics.common.BiometricUtils;
|
||||
import com.android.server.biometrics.common.ClientMonitor;
|
||||
import com.android.server.biometrics.common.EnumerateClient;
|
||||
import com.android.server.biometrics.common.Metrics;
|
||||
import com.android.server.biometrics.BiometricService;
|
||||
import com.android.server.biometrics.BiometricUtils;
|
||||
import com.android.server.biometrics.ClientMonitor;
|
||||
import com.android.server.biometrics.EnumerateClient;
|
||||
import com.android.server.biometrics.Metrics;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
@@ -147,22 +149,45 @@ public class FingerprintService extends BiometricService {
|
||||
@Override // Binder call
|
||||
public void authenticate(final IBinder token, final long opId, final int groupId,
|
||||
final IFingerprintServiceReceiver receiver, final int flags,
|
||||
final String opPackageName, final Bundle bundle,
|
||||
final IBiometricPromptReceiver dialogReceiver) {
|
||||
final String opPackageName) {
|
||||
final boolean restricted = isRestricted();
|
||||
final AuthenticationClientImpl client = new AuthenticationClientImpl(getContext(),
|
||||
mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
|
||||
mCurrentUserId, groupId, opId, restricted, opPackageName, bundle,
|
||||
dialogReceiver, mStatusBarService);
|
||||
mCurrentUserId, groupId, opId, restricted, opPackageName, null /* bundle */,
|
||||
null /* dialogReceiver */, mStatusBarService);
|
||||
|
||||
authenticateInternal(client, opId, opPackageName);
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void authenticateFromService(IBinder token, long opId, int groupId,
|
||||
IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
|
||||
Bundle bundle, IBiometricPromptReceiver dialogReceiver,
|
||||
int callingUid, int callingPid, int callingUserId) {
|
||||
checkPermission(MANAGE_BIOMETRIC);
|
||||
final boolean restricted = true; // BiometricPrompt is always restricted
|
||||
final AuthenticationClientImpl client = new AuthenticationClientImpl(getContext(),
|
||||
mDaemonWrapper, mHalDeviceId, token,
|
||||
new BiometricPromptServiceListenerImpl(receiver),
|
||||
mCurrentUserId, groupId, opId, restricted, opPackageName, bundle,
|
||||
dialogReceiver, mStatusBarService);
|
||||
authenticateInternal(client, opId, opPackageName, callingUid, callingPid,
|
||||
callingUserId);
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void cancelAuthentication(final IBinder token, final String opPackageName) {
|
||||
cancelAuthenticationInternal(token, opPackageName);
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void cancelAuthenticationFromService(final IBinder token, final String opPackageName,
|
||||
int callingUid, int callingPid, int callingUserId) {
|
||||
checkPermission(MANAGE_BIOMETRIC);
|
||||
cancelAuthenticationInternal(token, opPackageName,
|
||||
callingUid, callingPid, callingUserId);
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void setActiveUser(final int userId) {
|
||||
checkPermission(MANAGE_FINGERPRINT);
|
||||
@@ -331,6 +356,55 @@ public class FingerprintService extends BiometricService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives callbacks from the ClientMonitor implementations. The results are forwarded to
|
||||
* BiometricPrompt.
|
||||
*/
|
||||
private class BiometricPromptServiceListenerImpl implements ServiceListener {
|
||||
|
||||
// Use FingerprintManager to get strings, so BiometricPrompt interface is cleaner
|
||||
private FingerprintManager mFingerprintManager;
|
||||
private IBiometricPromptServiceReceiver mBiometricPromptServiceReceiver;
|
||||
|
||||
public BiometricPromptServiceListenerImpl(IBiometricPromptServiceReceiver receiver) {
|
||||
mBiometricPromptServiceReceiver = receiver;
|
||||
mFingerprintManager = (FingerprintManager)
|
||||
getContext().getSystemService(Context.FINGERPRINT_SERVICE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
|
||||
throws RemoteException {
|
||||
if (mBiometricPromptServiceReceiver != null) {
|
||||
mBiometricPromptServiceReceiver.onAcquired(deviceId, acquiredInfo,
|
||||
mFingerprintManager.getAcquiredString(acquiredInfo, vendorCode));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(long deviceId,
|
||||
BiometricAuthenticator.Identifier biometric, int userId) throws RemoteException {
|
||||
if (mBiometricPromptServiceReceiver != null) {
|
||||
mBiometricPromptServiceReceiver.onAuthenticationSucceeded(deviceId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed(long deviceId) throws RemoteException {
|
||||
if (mBiometricPromptServiceReceiver != null) {
|
||||
mBiometricPromptServiceReceiver.onAuthenticationFailed(deviceId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(long deviceId, int error, int vendorCode) throws RemoteException {
|
||||
if (mBiometricPromptServiceReceiver != null) {
|
||||
mBiometricPromptServiceReceiver.onError(deviceId, error,
|
||||
mFingerprintManager.getErrorString(error, vendorCode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives callbacks from the ClientMonitor implementations. The results are forwarded to
|
||||
* the FingerprintManager.
|
||||
|
||||
@@ -24,7 +24,7 @@ import android.util.Slog;
|
||||
import android.util.Xml;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.server.biometrics.common.BiometricUserState;
|
||||
import com.android.server.biometrics.BiometricUserState;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import android.text.TextUtils;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.server.biometrics.common.BiometricUtils;
|
||||
import com.android.server.biometrics.BiometricUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ import com.android.server.accessibility.AccessibilityManagerService;
|
||||
import com.android.server.am.ActivityManagerService;
|
||||
import com.android.server.am.ActivityTaskManagerService;
|
||||
import com.android.server.audio.AudioService;
|
||||
import com.android.server.biometrics.BiometricPromptService;
|
||||
import com.android.server.broadcastradio.BroadcastRadioService;
|
||||
import com.android.server.camera.CameraServiceProxy;
|
||||
import com.android.server.clipboard.ClipboardService;
|
||||
@@ -1551,18 +1552,30 @@ public final class SystemServer {
|
||||
}
|
||||
traceEnd();
|
||||
|
||||
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
|
||||
final boolean hasFeatureFace
|
||||
= mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE);
|
||||
final boolean hasFeatureFingerprint
|
||||
= mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
|
||||
|
||||
if (hasFeatureFace) {
|
||||
traceBeginAndSlog("StartFaceSensor");
|
||||
mSystemServiceManager.startService(FaceService.class);
|
||||
traceEnd();
|
||||
}
|
||||
|
||||
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
|
||||
if (hasFeatureFingerprint) {
|
||||
traceBeginAndSlog("StartFingerprintSensor");
|
||||
mSystemServiceManager.startService(FingerprintService.class);
|
||||
traceEnd();
|
||||
}
|
||||
|
||||
if (hasFeatureFace || hasFeatureFingerprint) {
|
||||
// Start this service after all biometric services.
|
||||
traceBeginAndSlog("StartBiometricPromptService");
|
||||
mSystemServiceManager.startService(BiometricPromptService.class);
|
||||
traceEnd();
|
||||
}
|
||||
|
||||
traceBeginAndSlog("StartBackgroundDexOptService");
|
||||
try {
|
||||
BackgroundDexOptService.schedule(context);
|
||||
|
||||
Reference in New Issue
Block a user