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

Commit 9b9d4b2e authored by Kevin Chyn's avatar Kevin Chyn Committed by Android (Google) Code Review
Browse files

Merge changes Ieabf61aa,Ib566e3f3

* changes:
  3/n: Start adding plumbing for some HAL callbacks
  2/n: Add HardwareAuthTokenUtils
parents 36ea0733 50b13e53
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -31,6 +31,10 @@ public final class Fingerprint extends BiometricAuthenticator.Identifier {
        mGroupId = groupId;
    }

    public Fingerprint(CharSequence name, int fingerId, long deviceId) {
        super(name, fingerId, deviceId);
    }

    private Fingerprint(Parcel in) {
        super(in.readString(), in.readInt(), in.readLong());
        mGroupId = in.readInt();
+138 −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 com.android.server.biometrics;

import static java.nio.ByteOrder.LITTLE_ENDIAN;

import android.hardware.keymaster.HardwareAuthToken;
import android.hardware.keymaster.Timestamp;

import java.nio.ByteOrder;

/**
 * Utilities for converting between old and new HardwareAuthToken types. See
 * {@link HardwareAuthToken}.
 */
public class HardwareAuthTokenUtils {
    public static byte[] toByteArray(HardwareAuthToken hat) {
        final byte[] array = new byte[69];

        // Version, first byte. Used in hw_auth_token.h but not HardwareAuthToken
        array[0] = 0;

        // Challenge, 1:8.
        writeLong(hat.challenge, array, 1 /* offset */);

        // UserId, 9:16.
        writeLong(hat.userId, array, 9 /* offset */);

        // AuthenticatorId, 17:24.
        writeLong(hat.authenticatorId, array, 17 /* offset */);

        // AuthenticatorType, 25:28.
        writeInt(flipIfNativelyLittle(hat.authenticatorType), array, 25 /* offset */);

        // Timestamp, 29:36.
        writeLong(flipIfNativelyLittle(hat.timestamp.milliSeconds), array, 29 /* offset */);

        // MAC, 37:69. Byte array.
        System.arraycopy(hat.mac, 0 /* srcPos */, array, 37 /* destPos */, hat.mac.length);

        return array;
    }

    public static HardwareAuthToken toHardwareAuthToken(byte[] array) {
        final HardwareAuthToken hardwareAuthToken = new HardwareAuthToken();

        // First byte is version, which doesn't not exist in HardwareAuthToken anymore
        // Next 8 bytes is the challenge.
        hardwareAuthToken.challenge = getLong(array, 1 /* offset */);

        // Next 8 bytes is the userId
        hardwareAuthToken.userId = getLong(array, 9 /* offset */);

        // Next 8 bytes is the authenticatorId.
        hardwareAuthToken.authenticatorId = getLong(array, 17 /* offset */);

        // Next 4 bytes is the authenticatorType.
        hardwareAuthToken.authenticatorType = flipIfNativelyLittle(getInt(array, 25 /* offset */));

        // Next 8 bytes is the timestamp.
        final Timestamp timestamp = new Timestamp();
        timestamp.milliSeconds = flipIfNativelyLittle(getLong(array, 29 /* offset */));
        hardwareAuthToken.timestamp = timestamp;

        // Last 32 bytes is the mac, 37:69
        hardwareAuthToken.mac = new byte[32];
        System.arraycopy(array, 37 /* srcPos */,
                hardwareAuthToken.mac,
                0 /* destPos */,
                32 /* length */);

        return hardwareAuthToken;
    }

    private static long flipIfNativelyLittle(long l) {
        if (LITTLE_ENDIAN == ByteOrder.nativeOrder()) {
            return Long.reverseBytes(l);
        }
        return l;
    }

    private static int flipIfNativelyLittle(int i) {
        if (LITTLE_ENDIAN == ByteOrder.nativeOrder()) {
            return Integer.reverseBytes(i);
        }
        return i;
    }

    private static void writeLong(long l, byte[] dest, int offset) {
        dest[offset + 0] = (byte) l;
        dest[offset + 1] = (byte) (l >> 8);
        dest[offset + 2] = (byte) (l >> 16);
        dest[offset + 3] = (byte) (l >> 24);
        dest[offset + 4] = (byte) (l >> 32);
        dest[offset + 5] = (byte) (l >> 40);
        dest[offset + 6] = (byte) (l >> 48);
        dest[offset + 7] = (byte) (l >> 56);
    }

    private static void writeInt(int i, byte[] dest, int offset) {
        dest[offset + 0] = (byte) i;
        dest[offset + 1] = (byte) (i >> 8);
        dest[offset + 2] = (byte) (i >> 16);
        dest[offset + 3] = (byte) (i >> 24);
    }

    private static long getLong(byte[] array, int offset) {
        long result = 0;
        // Lowest bit is LSB
        for (int i = 0; i < 8; i++) {
            result += (long) ((array[i + offset] & 0xffL) << (8 * i));
        }
        return result;
    }

    private static int getInt(byte[] array, int offset) {
        int result = 0;
        // Lowest bit is LSB
        for (int i = 0; i < 4; i++) {
            result += (int) (((int) array[i + offset] & 0xff) << (8 * i));
        }
        return result;
    }
}
+3 −2
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;

import com.android.server.biometrics.HardwareAuthTokenUtils;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.EnrollClient;
@@ -82,8 +83,8 @@ public class FingerprintEnrollClient extends EnrollClient<ISession> implements U
    protected void startHalOperation() {
        UdfpsHelper.showUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
        try {
            // TODO(b/170163175): Need a way to convert byte arrays to HardwareAuthToken
            getFreshDaemon().enroll(mSequentialId, null /* hat */);
            getFreshDaemon().enroll(mSequentialId,
                    HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken));
        } catch (RemoteException e) {
            Slog.e(TAG, "Remote exception when requesting enroll", e);
            onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, 0 /* vendorCode */);
+2 −2
Original line number Diff line number Diff line
@@ -79,8 +79,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
                            prop.commonProps.maxEnrollmentsPerUser,
                            prop.sensorType,
                            true /* resetLockoutRequiresHardwareAuthToken */);
            final Sensor sensor = new Sensor(getTag() + "/" + sensorId, internalProp,
                    gestureAvailabilityDispatcher);
            final Sensor sensor = new Sensor(getTag() + "/" + sensorId, mContext, mHandler,
                    internalProp, gestureAvailabilityDispatcher);

            mSensors.put(sensorId, sensor);
            Slog.d(getTag(), "Added: " + internalProp);
+99 −6
Original line number Diff line number Diff line
@@ -18,24 +18,40 @@ package com.android.server.biometrics.sensors.fingerprint.aidl;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.fingerprint.Error;
import android.hardware.biometrics.fingerprint.IFingerprint;
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.biometrics.fingerprint.ISessionCallback;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.keymaster.HardwareAuthToken;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Slog;

import com.android.server.biometrics.HardwareAuthTokenUtils;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.AcquisitionClient;
import com.android.server.biometrics.sensors.AuthenticationConsumer;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.ClientMonitor;
import com.android.server.biometrics.sensors.Interruptable;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Maintains the state of a single sensor within an instance of the
 * {@link android.hardware.biometrics.fingerprint.IFingerprint} HAL.
 */
class Sensor {
    @NonNull private final String mTag;
    @NonNull private final Context mContext;
    @NonNull private final Handler mHandler;
    @NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
    @NonNull private final BiometricScheduler mScheduler;

@@ -58,10 +74,12 @@ class Sensor {
        }
    }

    Sensor(@NonNull String tag,
    Sensor(@NonNull String tag, @NonNull Context context, @NonNull Handler handler,
            @NonNull FingerprintSensorPropertiesInternal sensorProperties,
            @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
        mTag = tag;
        mContext = context;
        mHandler = handler;
        mSensorProperties = sensorProperties;
        mScheduler = new BiometricScheduler(tag, gestureAvailabilityDispatcher);
        mLazySession = () -> mCurrentSession != null ? mCurrentSession.mSession : null;
@@ -89,27 +107,102 @@ class Sensor {

            @Override
            public void onAcquired(byte info, int vendorCode) {
                mHandler.post(() -> {
                    final ClientMonitor<?> client = mScheduler.getCurrentClient();
                    if (!(client instanceof AcquisitionClient)) {
                        Slog.e(mTag, "onAcquired for non-acquisition client: "
                                + Utils.getClientName(client));
                        return;
                    }

                    final AcquisitionClient<?> acquisitionClient = (AcquisitionClient<?>) client;
                    acquisitionClient.onAcquired(info, vendorCode);
                });
            }

            @Override
            public void onError(byte error, int vendorCode) {
                mHandler.post(() -> {
                    final ClientMonitor<?> client = mScheduler.getCurrentClient();
                    Slog.d(mTag, "onError"
                            + ", client: " + Utils.getClientName(client)
                            + ", error: " + error
                            + ", vendorCode: " + vendorCode);
                    if (!(client instanceof Interruptable)) {
                        Slog.e(mTag, "onError for non-error consumer: "
                                + Utils.getClientName(client));
                        return;
                    }

                    final Interruptable interruptable = (Interruptable) client;
                    interruptable.onError(error, vendorCode);

                    if (error == Error.HW_UNAVAILABLE) {
                        Slog.e(mTag, "Got ERROR_HW_UNAVAILABLE");
                        mCurrentSession = null;
                    }
                });
            }

            @Override
            public void onEnrollmentProgress(int enrollmentId, int remaining) {
                mHandler.post(() -> {
                    final ClientMonitor<?> client = mScheduler.getCurrentClient();
                    if (!(client instanceof FingerprintEnrollClient)) {
                        Slog.e(mTag, "onEnrollmentProgress for non-enroll client: "
                                + Utils.getClientName(client));
                        return;
                    }

                    final int currentUserId = client.getTargetUserId();
                    final CharSequence name = FingerprintUtils.getInstance()
                            .getUniqueName(mContext, currentUserId);
                    final Fingerprint fingerprint = new Fingerprint(name, enrollmentId, sensorId);

                    final FingerprintEnrollClient enrollClient = (FingerprintEnrollClient) client;
                    enrollClient.onEnrollResult(fingerprint, remaining);
                });
            }

            @Override
            public void onAuthenticationSucceeded(int enrollmentId, HardwareAuthToken hat) {
                mHandler.post(() -> {
                    final ClientMonitor<?> client = mScheduler.getCurrentClient();
                    if (!(client instanceof AuthenticationConsumer)) {
                        Slog.e(mTag, "onAuthenticationSucceeded for non-authentication consumer: "
                                + Utils.getClientName(client));
                        return;
                    }

                    final AuthenticationConsumer authenticationConsumer =
                            (AuthenticationConsumer) client;
                    final Fingerprint fp = new Fingerprint("", enrollmentId, sensorId);
                    final byte[] byteArray = HardwareAuthTokenUtils.toByteArray(hat);
                    final ArrayList<Byte> byteList = new ArrayList<>();
                    for (byte b : byteArray) {
                        byteList.add(b);
                    }

                    authenticationConsumer.onAuthenticated(fp, true /* authenticated */, byteList);
                });
            }

            @Override
            public void onAuthenticationFailed() {
                mHandler.post(() -> {
                    final ClientMonitor<?> client = mScheduler.getCurrentClient();
                    if (!(client instanceof AuthenticationConsumer)) {
                        Slog.e(mTag, "onAuthenticationFailed for non-authentication consumer: "
                                + Utils.getClientName(client));
                        return;
                    }

                    final AuthenticationConsumer authenticationConsumer =
                            (AuthenticationConsumer) client;
                    final Fingerprint fp = new Fingerprint("", 0 /* enrollmentId */, sensorId);
                    authenticationConsumer
                            .onAuthenticated(fp, false /* authenticated */, null /* hat */);
                });
            }

            @Override
Loading