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

Commit e4c6b835 authored by Ilya Matyukhin's avatar Ilya Matyukhin
Browse files

Take in a Surface then convert to a NativeHandle

We need to pass Surface objects to HIDL, but the Surface type is
currently not supported in HIDL. The closest thing to a Surface in HIDL
is a NativeHandle.

The initial plan was to convert Surface objects to NativeHandle objects
in framework, before passing them to HIDL. Unfortunately, there is no
canonical way to perform the conversion using just the framework APIs.
The only viable approach is to use the NDK conversion functions through
the JNI.

Bug: 150966034
Test: Manual, with a biometrics.face@1.1 HAL
Change-Id: I24f775b576fcab7c0260537d6f9cdc35a4794436
parent afd2b078
Loading
Loading
Loading
Loading
+0 −79
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.
                    }
                }
            }
        }
    }
}
+0 −26
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;
}
+8 −13
Original line number Diff line number Diff line
@@ -29,9 +29,7 @@ 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;
@@ -40,13 +38,13 @@ 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;
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
import android.view.Surface;

import com.android.internal.R;
import com.android.internal.os.SomeArgs;
@@ -251,15 +249,14 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan

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

    /**
@@ -277,13 +274,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.
     * @param surface  optional camera preview surface 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, @Nullable NativeHandle windowId) {
            EnrollmentCallback callback, int[] disabledFeatures, @Nullable Surface surface) {
        if (callback == null) {
            throw new IllegalArgumentException("Must supply an enrollment callback");
        }
@@ -298,12 +295,11 @@ 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, handle);
                        mContext.getOpPackageName(), disabledFeatures, surface);
            } catch (RemoteException e) {
                Log.w(TAG, "Remote exception in enroll: ", e);
                // Though this may not be a hardware issue, it will cause apps to give up or
@@ -313,7 +309,6 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
                                0 /* vendorCode */));
            } finally {
                Trace.endSection();
                BiometricNativeHandleUtils.close(handle);
            }
        }
    }
+2 −2
Original line number Diff line number Diff line
@@ -15,11 +15,11 @@
 */
package android.hardware.face;

import android.hardware.biometrics.IBiometricNativeHandle;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.face.IFaceServiceReceiver;
import android.hardware.face.Face;
import android.view.Surface;

/**
 * Communication channel from client to the face service. These methods are all require the
@@ -52,7 +52,7 @@ interface IFaceService {

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

    // Start remote face enrollment
    void enrollRemotely(int userId, IBinder token, in byte [] cryptoToken, IFaceServiceReceiver receiver,
+12 −20
Original line number Diff line number Diff line
@@ -32,9 +32,7 @@ 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;
@@ -43,12 +41,12 @@ 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;
import android.security.identity.IdentityCredential;
import android.util.Slog;
import android.view.Surface;

import java.security.Signature;
import java.util.List;
@@ -419,17 +417,17 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing

    /**
     * Defaults to {@link FingerprintManager#authenticate(CryptoObject, CancellationSignal, int,
     * AuthenticationCallback, Handler, int, NativeHandle)} with {@code windowId} set to null.
     * AuthenticationCallback, Handler, int, Surface)} with {@code surface} set to null.
     *
     * @see FingerprintManager#authenticate(CryptoObject, CancellationSignal, int,
     * AuthenticationCallback, Handler, int, NativeHandle)
     * AuthenticationCallback, Handler, int, Surface)
     *
     * @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 */);
        authenticate(crypto, cancel, flags, callback, handler, userId, null /* surface */);
    }

    /**
@@ -437,14 +435,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
     * 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
     * @param surface 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,
            @Nullable NativeHandle windowId) {
            @Nullable Surface surface) {
        if (callback == null) {
            throw new IllegalArgumentException("Must supply an authentication callback");
        }
@@ -459,14 +457,13 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
        }

        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(), handle);
                        mContext.getOpPackageName(), surface);
            } catch (RemoteException e) {
                Slog.w(TAG, "Remote exception while authenticating: ", e);
                // Though this may not be a hardware issue, it will cause apps to give up or try
@@ -474,25 +471,23 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
                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.
     * EnrollmentCallback, Surface)} with {@code surface} set to null.
     *
     * @see FingerprintManager#enroll(byte[], CancellationSignal, int, int, EnrollmentCallback,
     * NativeHandle)
     * Surface)
     *
     * @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 */);
        enroll(token, cancel, flags, userId, callback, null /* surface */);
    }

    /**
@@ -513,7 +508,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
     */
    @RequiresPermission(MANAGE_FINGERPRINT)
    public void enroll(byte [] token, CancellationSignal cancel, int flags,
            int userId, EnrollmentCallback callback, @Nullable NativeHandle windowId) {
            int userId, EnrollmentCallback callback, @Nullable Surface surface) {
        if (userId == UserHandle.USER_CURRENT) {
            userId = getCurrentUserId();
        }
@@ -531,11 +526,10 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
        }

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