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

Commit 185efbaf authored by Ilya Matyukhin's avatar Ilya Matyukhin Committed by Android (Google) Code Review
Browse files

Merge "Add support for fingerprint@2.2 and face@1.1"

parents dc08a378 ef410e3c
Loading
Loading
Loading
Loading
+79 −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.biometrics;

import android.os.NativeHandle;
import android.os.ParcelFileDescriptor;

import java.io.IOException;

/**
 * A class that contains utilities for IBiometricNativeHandle.
 *
 * @hide
 */
public final class BiometricNativeHandleUtils {

    private BiometricNativeHandleUtils() {
    }

    /**
     * Converts a {@link NativeHandle} into an {@link IBiometricNativeHandle} by duplicating the
     * underlying file descriptors.
     *
     * Both the original and new handle must be closed after use.
     *
     * @param h {@link NativeHandle}. Usually used to identify a WindowManager window. Can be null.
     * @return A {@link IBiometricNativeHandle} representation of {@code h}. Will be null if
     * {@code h} or its raw file descriptors are null.
     */
    public static IBiometricNativeHandle dup(NativeHandle h) {
        IBiometricNativeHandle handle = null;
        if (h != null && h.getFileDescriptors() != null && h.getInts() != null) {
            handle = new IBiometricNativeHandle();
            handle.ints = h.getInts().clone();
            handle.fds = new ParcelFileDescriptor[h.getFileDescriptors().length];
            for (int i = 0; i < h.getFileDescriptors().length; ++i) {
                try {
                    handle.fds[i] = ParcelFileDescriptor.dup(h.getFileDescriptors()[i]);
                } catch (IOException e) {
                    return null;
                }
            }
        }
        return handle;
    }

    /**
     * Closes the handle's file descriptors.
     *
     * @param h {@link IBiometricNativeHandle} handle.
     */
    public static void close(IBiometricNativeHandle h) {
        if (h != null) {
            for (ParcelFileDescriptor fd : h.fds) {
                if (fd != null) {
                    try {
                        fd.close();
                    } catch (IOException e) {
                        // do nothing.
                    }
                }
            }
        }
    }
}
+26 −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.biometrics;

/**
 * Representation of a native handle.
 * Copied from /common/aidl/android/hardware/common/NativeHandle.aidl
 * @hide
 */
parcelable IBiometricNativeHandle {
    ParcelFileDescriptor[] fds;
    int[] ints;
}
+78 −8
Original line number Diff line number Diff line
@@ -29,7 +29,9 @@ import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricFaceConstants;
import android.hardware.biometrics.BiometricNativeHandleUtils;
import android.hardware.biometrics.CryptoObject;
import android.hardware.biometrics.IBiometricNativeHandle;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.os.Binder;
import android.os.CancellationSignal;
@@ -38,6 +40,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.NativeHandle;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.Trace;
@@ -244,6 +247,19 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
        }
    }

    /**
     * Defaults to {@link FaceManager#enroll(int, byte[], CancellationSignal, EnrollmentCallback,
     * int[], NativeHandle)} with {@code windowId} set to null.
     *
     * @see FaceManager#enroll(int, byte[], CancellationSignal, EnrollmentCallback, int[],
     * NativeHandle)
     */
    @RequiresPermission(MANAGE_BIOMETRIC)
    public void enroll(int userId, byte[] token, CancellationSignal cancel,
            EnrollmentCallback callback, int[] disabledFeatures) {
        enroll(userId, token, cancel, callback, disabledFeatures, null /* windowId */);
    }

    /**
     * Request face authentication enrollment. This call operates the face authentication hardware
     * and starts capturing images. Progress will be indicated by callbacks to the
@@ -259,11 +275,13 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
     * @param flags    optional flags
     * @param userId   the user to whom this face will belong to
     * @param callback an object to receive enrollment events
     * @param windowId optional ID of a camera preview window for a single-camera device. Must be
     *                 null if not used.
     * @hide
     */
    @RequiresPermission(MANAGE_BIOMETRIC)
    public void enroll(int userId, byte[] token, CancellationSignal cancel,
            EnrollmentCallback callback, int[] disabledFeatures) {
            EnrollmentCallback callback, int[] disabledFeatures, @Nullable NativeHandle windowId) {
        if (callback == null) {
            throw new IllegalArgumentException("Must supply an enrollment callback");
        }
@@ -278,20 +296,72 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
        }

        if (mService != null) {
            IBiometricNativeHandle handle = BiometricNativeHandleUtils.dup(windowId);
            try {
                mEnrollmentCallback = callback;
                Trace.beginSection("FaceManager#enroll");
                mService.enroll(userId, mToken, token, mServiceReceiver,
                        mContext.getOpPackageName(), disabledFeatures);
                        mContext.getOpPackageName(), disabledFeatures, handle);
            } catch (RemoteException e) {
                Log.w(TAG, "Remote exception in enroll: ", e);
                if (callback != null) {
                // Though this may not be a hardware issue, it will cause apps to give up or
                // try again later.
                callback.onEnrollmentError(FACE_ERROR_HW_UNAVAILABLE,
                        getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
                                0 /* vendorCode */));
            } finally {
                Trace.endSection();
                BiometricNativeHandleUtils.close(handle);
            }
        }
    }

    /**
     * Request face authentication enrollment for a remote client, for example Android Auto.
     * This call operates the face authentication hardware and starts capturing images.
     * Progress will be indicated by callbacks to the
     * {@link EnrollmentCallback} object. It terminates when
     * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or
     * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at
     * which point the object is no longer valid. The operation can be canceled by using the
     * provided cancel object.
     *
     * @param token    a unique token provided by a recent creation or verification of device
     *                 credentials (e.g. pin, pattern or password).
     * @param cancel   an object that can be used to cancel enrollment
     * @param userId   the user to whom this face will belong to
     * @param callback an object to receive enrollment events
     * @hide
     */
    @RequiresPermission(MANAGE_BIOMETRIC)
    public void enrollRemotely(int userId, byte[] token, CancellationSignal cancel,
            EnrollmentCallback callback, int[] disabledFeatures) {
        if (callback == null) {
            throw new IllegalArgumentException("Must supply an enrollment callback");
        }

        if (cancel != null) {
            if (cancel.isCanceled()) {
                Log.w(TAG, "enrollRemotely is already canceled.");
                return;
            } else {
                cancel.setOnCancelListener(new OnEnrollCancelListener());
            }
        }

        if (mService != null) {
            try {
                mEnrollmentCallback = callback;
                Trace.beginSection("FaceManager#enrollRemotely");
                mService.enrollRemotely(userId, mToken, token, mServiceReceiver,
                        mContext.getOpPackageName(), disabledFeatures);
            } catch (RemoteException e) {
                Log.w(TAG, "Remote exception in enrollRemotely: ", e);
                // Though this may not be a hardware issue, it will cause apps to give up or
                // try again later.
                callback.onEnrollmentError(FACE_ERROR_HW_UNAVAILABLE,
                        getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
                                0 /* vendorCode */));
            } finally {
                Trace.endSection();
            }
+5 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package android.hardware.face;

import android.hardware.biometrics.IBiometricNativeHandle;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.face.IFaceServiceReceiver;
@@ -51,6 +52,10 @@ interface IFaceService {

    // Start face enrollment
    void enroll(int userId, IBinder token, in byte [] cryptoToken, IFaceServiceReceiver receiver,
            String opPackageName, in int [] disabledFeatures, in IBiometricNativeHandle windowId);

    // Start remote face enrollment
    void enrollRemotely(int userId, IBinder token, in byte [] cryptoToken, IFaceServiceReceiver receiver,
            String opPackageName, in int [] disabledFeatures);

    // Cancel enrollment in progress
+63 −21
Original line number Diff line number Diff line
@@ -32,7 +32,9 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricNativeHandleUtils;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.IBiometricNativeHandle;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.os.Binder;
import android.os.CancellationSignal;
@@ -41,6 +43,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.NativeHandle;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -402,16 +405,34 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
        }
    }

    /**
     * Defaults to {@link FingerprintManager#authenticate(CryptoObject, CancellationSignal, int,
     * AuthenticationCallback, Handler, int, NativeHandle)} with {@code windowId} set to null.
     *
     * @see FingerprintManager#authenticate(CryptoObject, CancellationSignal, int,
     * AuthenticationCallback, Handler, int, NativeHandle)
     *
     * @hide
     */
    @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
    public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
            int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) {
        authenticate(crypto, cancel, flags, callback, handler, userId, null /* windowId */);
    }

    /**
     * Per-user version, see {@link FingerprintManager#authenticate(CryptoObject,
     * CancellationSignal, int, AuthenticationCallback, Handler)}. This version does not
     * display the BiometricPrompt.
     * @param userId the user ID that the fingerprint hardware will authenticate for.
     * @param windowId for optical fingerprint sensors that require active illumination by the OLED
     *        display. Should be null for devices that don't require illumination.
     * @hide
     */
    @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
    public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
            int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) {
            int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId,
            @Nullable NativeHandle windowId) {
        if (callback == null) {
            throw new IllegalArgumentException("Must supply an authentication callback");
        }
@@ -425,25 +446,43 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
            }
        }

        if (mService != null) try {
        if (mService != null) {
            IBiometricNativeHandle handle = BiometricNativeHandleUtils.dup(windowId);
            try {
                useHandler(handler);
                mAuthenticationCallback = callback;
                mCryptoObject = crypto;
                long sessionId = crypto != null ? crypto.getOpId() : 0;
                mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,
                    mContext.getOpPackageName());
                        mContext.getOpPackageName(), handle);
            } catch (RemoteException e) {
                Slog.w(TAG, "Remote exception while authenticating: ", e);
            if (callback != null) {
                // Though this may not be a hardware issue, it will cause apps to give up or try
                // again later.
                callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
                        getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE,
                                0 /* vendorCode */));
            } finally {
                BiometricNativeHandleUtils.close(handle);
            }
        }
    }

    /**
     * Defaults to {@link FingerprintManager#enroll(byte[], CancellationSignal, int, int,
     * EnrollmentCallback, NativeHandle)} with {@code windowId} set to null.
     *
     * @see FingerprintManager#enroll(byte[], CancellationSignal, int, int, EnrollmentCallback,
     * NativeHandle)
     *
     * @hide
     */
    @RequiresPermission(MANAGE_FINGERPRINT)
    public void enroll(byte [] token, CancellationSignal cancel, int flags,
            int userId, EnrollmentCallback callback) {
        enroll(token, cancel, flags, userId, callback, null /* windowId */);
    }

    /**
     * Request fingerprint enrollment. This call warms up the fingerprint hardware
     * and starts scanning for fingerprints. Progress will be indicated by callbacks to the
@@ -462,7 +501,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
     */
    @RequiresPermission(MANAGE_FINGERPRINT)
    public void enroll(byte [] token, CancellationSignal cancel, int flags,
            int userId, EnrollmentCallback callback) {
            int userId, EnrollmentCallback callback, @Nullable NativeHandle windowId) {
        if (userId == UserHandle.USER_CURRENT) {
            userId = getCurrentUserId();
        }
@@ -479,18 +518,21 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
            }
        }

        if (mService != null) try {
        if (mService != null) {
            IBiometricNativeHandle handle = BiometricNativeHandleUtils.dup(windowId);
            try {
                mEnrollmentCallback = callback;
                mService.enroll(mToken, token, userId, mServiceReceiver, flags,
                    mContext.getOpPackageName());
                        mContext.getOpPackageName(), handle);
            } catch (RemoteException e) {
                Slog.w(TAG, "Remote exception in enroll: ", e);
            if (callback != null) {
                // Though this may not be a hardware issue, it will cause apps to give up or try
                // again later.
                callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
                        getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE,
                                0 /* vendorCode */));
            } finally {
                BiometricNativeHandleUtils.close(handle);
            }
        }
    }
Loading