Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1f9cce1b authored by Kevin Chyn's avatar Kevin Chyn
Browse files

Update authentication when encrypted or lockout

Fingerprint authentication should not expose accept/reject/lockout
when the user is encrypted or locked out. This is possible with
IBiometricsFingerprint@2.1 since lockout is controlled by the framework.

IBiometricsFace@1.0 does not support this since lockout is controlled
in the HAL (or lower). Adds enough plumbing on SysUI so that it will
work once the HAL supports it.

Introduces FingerprintDetectClient, which treats HAL accept/reject as
the same, and does not increase the framework's lockout counter.

Introduces FingerprintManager/FaceManager#getSensorProperties so callers
can determine features before invoking certain code paths, such as
finger/face detect.

Bug: 79776455

Test: On fingerprint device, during encrypted or lockdown, any finger
      works, lockout never occurs
Test: Test no effect on face device
Test: atest KeyguardUpdateMonitorTest

Change-Id: I6c9717d1f8ed3e844b3d92727396e2ce2e7fd94f
parent 4f0e5060
Loading
Loading
Loading
Loading
+93 −1
Original line number Diff line number Diff line
/**
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
@@ -70,11 +70,13 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
    private static final int MSG_GET_FEATURE_COMPLETED = 106;
    private static final int MSG_SET_FEATURE_COMPLETED = 107;
    private static final int MSG_CHALLENGE_GENERATED = 108;
    private static final int MSG_FACE_DETECTED = 109;

    private final IFaceService mService;
    private final Context mContext;
    private IBinder mToken = new Binder();
    private AuthenticationCallback mAuthenticationCallback;
    private FaceDetectionCallback mFaceDetectionCallback;
    private EnrollmentCallback mEnrollmentCallback;
    private RemovalCallback mRemovalCallback;
    private SetFeatureCallback mSetFeatureCallback;
@@ -102,6 +104,12 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
                    face).sendToTarget();
        }

        @Override // binder call
        public void onFaceDetected(int sensorId, int userId, boolean isStrongBiometric) {
            mHandler.obtainMessage(MSG_FACE_DETECTED, sensorId, userId, isStrongBiometric)
                    .sendToTarget();
        }

        @Override // binder call
        public void onAuthenticationFailed() {
            mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();
@@ -250,6 +258,34 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
        }
    }

    /**
     * Uses the face hardware to detect for the presence of a face, without giving details about
     * accept/reject/lockout.
     * @hide
     */
    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
    public void detectFace(@NonNull CancellationSignal cancel,
            @NonNull FaceDetectionCallback callback, int userId) {
        if (mService == null) {
            return;
        }

        if (cancel.isCanceled()) {
            Slog.w(TAG, "Detection already cancelled");
            return;
        } else {
            cancel.setOnCancelListener(new OnFaceDetectionCancelListener());
        }

        mFaceDetectionCallback = callback;

        try {
            mService.detectFace(mToken, userId, mServiceReceiver, mContext.getOpPackageName());
        } catch (RemoteException e) {
            Slog.w(TAG, "Remote exception when requesting finger detect", e);
        }
    }

    /**
     * Defaults to {@link FaceManager#enroll(int, byte[], CancellationSignal, EnrollmentCallback,
     * int[], Surface)} with {@code surface} set to null.
@@ -580,6 +616,24 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
        return false;
    }

    /**
     * Get statically configured sensor properties.
     * @hide
     */
    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
    @NonNull
    public FaceSensorProperties getSensorProperties() {
        try {
            if (mService == null || !mService.isHardwareDetected(mContext.getOpPackageName())) {
                return new FaceSensorProperties();
            }
            return mService.getSensorProperties(mContext.getOpPackageName());
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
        }
        return new FaceSensorProperties();
    }

    /**
     * @hide
     */
@@ -639,6 +693,18 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
        }
    }

    private void cancelFaceDetect() {
        if (mService == null) {
            return;
        }

        try {
            mService.cancelFaceDetect(mToken, mContext.getOpPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * @hide
     */
@@ -895,6 +961,13 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
        }
    }

    /**
     * @hide
     */
    public interface FaceDetectionCallback {
        void onFaceDetected(int sensorId, int userId, boolean isStrongBiometric);
    }

    /**
     * Callback structure provided to {@link FaceManager#enroll(long,
     * EnrollmentCallback, CancellationSignal, int). Users of {@link #FaceAuthenticationManager()}
@@ -1026,6 +1099,13 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
        }
    }

    private class OnFaceDetectionCancelListener implements OnCancelListener {
        @Override
        public void onCancel() {
            cancelFaceDetect();
        }
    }

    private class MyHandler extends Handler {
        private MyHandler(Context context) {
            super(context.getMainLooper());
@@ -1072,6 +1152,10 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
                case MSG_CHALLENGE_GENERATED:
                    sendChallengeGenerated((long) msg.obj /* challenge */);
                    break;
                case MSG_FACE_DETECTED:
                    sendFaceDetected(msg.arg1 /* sensorId */, msg.arg2 /* userId */,
                            (boolean) msg.obj /* isStrongBiometric */);
                    break;
                default:
                    Slog.w(TAG, "Unknown message: " + msg.what);
            }
@@ -1100,6 +1184,14 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
        mGenerateChallengeCallback.onGenerateChallengeResult(challenge);
    }

    private void sendFaceDetected(int sensorId, int userId, boolean isStrongBiometric) {
        if (mFaceDetectionCallback == null) {
            Slog.e(TAG, "sendFaceDetected, callback null");
            return;
        }
        mFaceDetectionCallback.onFaceDetected(sensorId, userId, isStrongBiometric);
    }

    private void sendRemovedResult(Face face, int remaining) {
        if (mRemovalCallback == null) {
            return;
+18 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.face;

parcelable FaceSensorProperties;
 No newline at end of file
+70 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.face;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Container for face sensor properties.
 * @hide
 */
public class FaceSensorProperties implements Parcelable {

    public final boolean supportsFaceDetection;

    /**
     * Creates a SensorProperties class with safe default values
     */
    public FaceSensorProperties() {
        supportsFaceDetection = false;
    }

    /**
     * Initializes SensorProperties with specified values
     */
    public FaceSensorProperties(boolean supportsFaceDetection) {
        this.supportsFaceDetection = supportsFaceDetection;
    }

    protected FaceSensorProperties(Parcel in) {
        supportsFaceDetection = in.readBoolean();
    }

    public static final Creator<FaceSensorProperties> CREATOR =
            new Creator<FaceSensorProperties>() {
        @Override
        public FaceSensorProperties createFromParcel(Parcel in) {
            return new FaceSensorProperties(in);
        }

        @Override
        public FaceSensorProperties[] newArray(int size) {
            return new FaceSensorProperties[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeBoolean(supportsFaceDetection);
    }
}
+11 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.face.IFaceServiceReceiver;
import android.hardware.face.Face;
import android.hardware.face.FaceSensorProperties;
import android.view.Surface;

/**
@@ -31,6 +32,10 @@ interface IFaceService {
    void authenticate(IBinder token, long operationId, int userid, IFaceServiceReceiver receiver,
            String opPackageName);

    // Uses the face hardware to detect for the presence of a face, without giving details
    // about accept/reject/lockout.
    void detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName);

    // This method prepares the service to start authenticating, but doesn't start authentication.
    // This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be
    // called from BiometricService. The additional uid, pid, userId arguments should be determined
@@ -46,6 +51,9 @@ interface IFaceService {
    // Cancel authentication for the given sessionId
    void cancelAuthentication(IBinder token, String opPackageName);

    // Cancel face detection
    void cancelFaceDetect(IBinder token, String opPackageName);

    // Same as above, with extra arguments.
    void cancelAuthenticationFromService(IBinder token, String opPackageName,
            int callingUid, int callingPid, int callingUserId);
@@ -80,6 +88,9 @@ interface IFaceService {
    // Determine if a user has at least one enrolled face
    boolean hasEnrolledFaces(int userId, String opPackageName);

    // Retrieve static sensor properties
    FaceSensorProperties getSensorProperties(String opPackageName);

    // Return the LockoutTracker status for the specified user
    int getLockoutModeForUser(int userId);

+1 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ oneway interface IFaceServiceReceiver {
    void onEnrollResult(in Face face, int remaining);
    void onAcquired(int acquiredInfo, int vendorCode);
    void onAuthenticationSucceeded(in Face face, int userId, boolean isStrongBiometric);
    void onFaceDetected(int sensorId, int userId, boolean isStrongBiometric);
    void onAuthenticationFailed();
    void onError(int error, int vendorCode);
    void onRemoved(in Face face, int remaining);
Loading