Merge changes from topic "biometric-prompt-service"

* changes:
  Add BiometricPromptService
  Remove common biometric directory
This commit is contained in:
TreeHugger Robot
2018-08-31 01:21:07 +00:00
committed by Android (Google) Code Review
37 changed files with 953 additions and 469 deletions

View File

@@ -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",

View File

@@ -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

View File

@@ -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

View File

@@ -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!");
}
}

View File

@@ -175,5 +175,5 @@ public interface BiometricConstants {
/**
* @hide
*/
int BIOMETRICT_ACQUIRED_VENDOR_BASE = 1000;
int BIOMETRIC_ACQUIRED_VENDOR_BASE = 1000;
}

View File

@@ -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
*/

View File

@@ -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));
});
}
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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"

View File

@@ -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 -->

View File

@@ -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" />

View File

@@ -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" />

View File

@@ -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() {

View File

@@ -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;

View File

@@ -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;
}
}
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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.

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);