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

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

Merge changes from topic "clientmonitor-cleanup3"

* changes:
  Clear identity when checking BiometricService#isStrongBiometric()
  17/n: Make generateChallenge/revokeChallenge ClientMonitors
  16/n: Introduce ClientMonitor#FinishCallback
  15/n: Combine EnumerateClient into InternalEnumerateClient
  14/n: Remove the use of groupId
  13/n: Remove the use of DaemonWrapper
parents 58fd2766 74b61eb9
Loading
Loading
Loading
Loading
+89 −22
Original line number Diff line number Diff line
@@ -41,7 +41,6 @@ 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;

@@ -49,6 +48,9 @@ import com.android.internal.R;
import com.android.internal.os.SomeArgs;

import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * A class that coordinates access to the face authentication hardware.
@@ -67,6 +69,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
    private static final int MSG_REMOVED = 105;
    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 IFaceService mService;
    private final Context mContext;
@@ -76,6 +79,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
    private RemovalCallback mRemovalCallback;
    private SetFeatureCallback mSetFeatureCallback;
    private GetFeatureCallback mGetFeatureCallback;
    private GenerateChallengeCallback mGenerateChallengeCallback;
    private CryptoObject mCryptoObject;
    private Face mRemovalFace;
    private Handler mHandler;
@@ -126,6 +130,17 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
            args.arg2 = value;
            mHandler.obtainMessage(MSG_GET_FEATURE_COMPLETED, args).sendToTarget();
        }

        @Override
        public void onChallengeGenerated(long challenge) {
            if (mGenerateChallengeCallback instanceof InternalGenerateChallengeCallback) {
                // Perform this on system_server thread, since the application's thread is
                // blocked waiting for the result
                mGenerateChallengeCallback.onGenerateChallengeResult(challenge);
            } else {
                mHandler.obtainMessage(MSG_CHALLENGE_GENERATED, challenge).sendToTarget();
            }
        }
    };

    /**
@@ -207,7 +222,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan

        if (cancel != null) {
            if (cancel.isCanceled()) {
                Log.w(TAG, "authentication already canceled");
                Slog.w(TAG, "authentication already canceled");
                return;
            } else {
                cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
@@ -224,7 +239,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
                mService.authenticate(mToken, operationId, userId, mServiceReceiver,
                        flags, mContext.getOpPackageName());
            } catch (RemoteException e) {
                Log.w(TAG, "Remote exception while authenticating: ", 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.
@@ -278,7 +293,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan

        if (cancel != null) {
            if (cancel.isCanceled()) {
                Log.w(TAG, "enrollment already canceled");
                Slog.w(TAG, "enrollment already canceled");
                return;
            } else {
                cancel.setOnCancelListener(new OnEnrollCancelListener());
@@ -292,7 +307,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
                mService.enroll(userId, mToken, token, mServiceReceiver,
                        mContext.getOpPackageName(), disabledFeatures, surface);
            } catch (RemoteException e) {
                Log.w(TAG, "Remote exception in enroll: ", 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 again later.
                callback.onEnrollmentError(FACE_ERROR_HW_UNAVAILABLE,
@@ -330,7 +345,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan

        if (cancel != null) {
            if (cancel.isCanceled()) {
                Log.w(TAG, "enrollRemotely is already canceled.");
                Slog.w(TAG, "enrollRemotely is already canceled.");
                return;
            } else {
                cancel.setOnCancelListener(new OnEnrollCancelListener());
@@ -344,7 +359,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
                mService.enrollRemotely(userId, mToken, token, mServiceReceiver,
                        mContext.getOpPackageName(), disabledFeatures);
            } catch (RemoteException e) {
                Log.w(TAG, "Remote exception in enrollRemotely: ", e);
                Slog.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,
@@ -357,22 +372,56 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
    }

    /**
     * Requests an auth token to tie sensitive operations to the confirmation of
     * existing device credentials (e.g. pin/pattern/password).
     * Same as {@link #generateChallenge(GenerateChallengeCallback)}, except blocks until the
     * TEE/hardware operation is complete.
     * @return challenge generated in the TEE/hardware
     * @hide
     */
    @RequiresPermission(MANAGE_BIOMETRIC)
    public long generateChallengeBlocking() {
        final AtomicReference<Long> result = new AtomicReference<>();
        final CountDownLatch latch = new CountDownLatch(1);
        final GenerateChallengeCallback callback = new InternalGenerateChallengeCallback() {
            @Override
            public void onGenerateChallengeResult(long challenge) {
                result.set(challenge);
                latch.countDown();
            }
        };

        generateChallenge(callback);

        try {
            latch.await(1, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Slog.e(TAG, "Interrupted while generatingChallenge", e);
            e.printStackTrace();
        }
        return result.get();
    }

    /**
     * Generates a unique random challenge in the TEE. A typical use case is to have it wrapped in a
     * HardwareAuthenticationToken, minted by Gatekeeper upon PIN/Pattern/Password verification.
     * The HardwareAuthenticationToken can then be sent to the biometric HAL together with a
     * request to perform sensitive operation(s) (for example enroll or setFeature), represented
     * by the challenge. Doing this ensures that a the sensitive operation cannot be performed
     * unless the user has entered confirmed PIN/Pattern/Password.
     *
     * @see com.android.server.locksettings.LockSettingsService
     *
     * @hide
     */
    @RequiresPermission(MANAGE_BIOMETRIC)
    public long generateChallenge() {
        long result = 0;
    public void generateChallenge(GenerateChallengeCallback callback) {
        if (mService != null) {
            try {
                result = mService.generateChallenge(mToken);
                mGenerateChallengeCallback = callback;
                mService.generateChallenge(mToken, mServiceReceiver, mContext.getOpPackageName());
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
        return result;
    }

    /**
@@ -381,16 +430,14 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
     * @hide
     */
    @RequiresPermission(MANAGE_BIOMETRIC)
    public int revokeChallenge() {
        int result = 0;
    public void revokeChallenge() {
        if (mService != null) {
            try {
                result = mService.revokeChallenge(mToken);
                mService.revokeChallenge(mToken, mContext.getOpPackageName());
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
        return result;
    }

    /**
@@ -458,7 +505,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
                mService.remove(mToken, face.getBiometricId(), userId, mServiceReceiver,
                        mContext.getOpPackageName());
            } catch (RemoteException e) {
                Log.w(TAG, "Remote exception in remove: ", e);
                Slog.w(TAG, "Remote exception in remove: ", e);
                if (callback != null) {
                    callback.onRemovalError(face, FACE_ERROR_HW_UNAVAILABLE,
                            getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
@@ -546,7 +593,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
                throw e.rethrowFromSystemServer();
            }
        } else {
            Log.w(TAG, "isFaceHardwareDetected(): Service not connected!");
            Slog.w(TAG, "isFaceHardwareDetected(): Service not connected!");
        }
        return false;
    }
@@ -586,7 +633,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
                throw e.rethrowFromSystemServer();
            }
        } else {
            Log.w(TAG, "addLockoutResetCallback(): Service not connected!");
            Slog.w(TAG, "addLockoutResetCallback(): Service not connected!");
        }
    }

@@ -967,6 +1014,16 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
        public abstract void onCompleted(boolean success, int feature, boolean value);
    }

    /**
     * @hide
     */
    public abstract static class GenerateChallengeCallback {
        public abstract void onGenerateChallengeResult(long challenge);
    }

    private abstract static class InternalGenerateChallengeCallback
            extends GenerateChallengeCallback {}

    private class OnEnrollCancelListener implements OnCancelListener {
        @Override
        public void onCancel() {
@@ -1030,8 +1087,11 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
                            (boolean) args.arg2 /* value */);
                    args.recycle();
                    break;
                case MSG_CHALLENGE_GENERATED:
                    sendChallengeGenerated((long) msg.obj /* challenge */);
                    break;
                default:
                    Log.w(TAG, "Unknown message: " + msg.what);
                    Slog.w(TAG, "Unknown message: " + msg.what);
            }
            Trace.endSection();
        }
@@ -1051,12 +1111,19 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
        mGetFeatureCallback.onCompleted(success, feature, value);
    }

    private void sendChallengeGenerated(long challenge) {
        if (mGenerateChallengeCallback == null) {
            return;
        }
        mGenerateChallengeCallback.onGenerateChallengeResult(challenge);
    }

    private void sendRemovedResult(Face face, int remaining) {
        if (mRemovalCallback == null) {
            return;
        }
        if (face == null) {
            Log.e(TAG, "Received MSG_REMOVED, but face is null");
            Slog.e(TAG, "Received MSG_REMOVED, but face is null");
            return;
        }
        mRemovalCallback.onRemovalSucceeded(face, remaining);
+2 −2
Original line number Diff line number Diff line
@@ -72,10 +72,10 @@ interface IFaceService {
    boolean isHardwareDetected(String opPackageName);

    // Get a pre-enrollment authentication token
    long generateChallenge(IBinder token);
    void generateChallenge(IBinder token, IFaceServiceReceiver receiver, String opPackageName);

    // Finish an enrollment sequence and invalidate the authentication token
    int revokeChallenge(IBinder token);
    void revokeChallenge(IBinder token, String opPackageName);

    // Determine if a user has at least one enrolled face
    boolean hasEnrolledFaces(int userId, String opPackageName);
+1 −0
Original line number Diff line number Diff line
@@ -30,4 +30,5 @@ oneway interface IFaceServiceReceiver {
    void onRemoved(in Face face, int remaining);
    void onFeatureSet(boolean success, int feature);
    void onFeatureGet(boolean success, int feature, boolean value);
    void onChallengeGenerated(long challenge);
}
+87 −18
Original line number Diff line number Diff line
@@ -50,7 +50,10 @@ import android.view.Surface;

import java.security.Signature;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

import javax.crypto.Cipher;
import javax.crypto.Mac;
@@ -75,6 +78,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
    private static final int MSG_AUTHENTICATION_FAILED = 103;
    private static final int MSG_ERROR = 104;
    private static final int MSG_REMOVED = 105;
    private static final int MSG_CHALLENGE_GENERATED = 106;

    private IFingerprintService mService;
    private Context mContext;
@@ -82,6 +86,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
    private AuthenticationCallback mAuthenticationCallback;
    private EnrollmentCallback mEnrollmentCallback;
    private RemovalCallback mRemovalCallback;
    private GenerateChallengeCallback mGenerateChallengeCallback;
    private CryptoObject mCryptoObject;
    private Fingerprint mRemovalFingerprint;
    private Handler mHandler;
@@ -345,6 +350,16 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
        public void onLockoutReset() { }
    };

    /**
     * @hide
     */
    public abstract static class GenerateChallengeCallback {
        public abstract void onChallengeGenerated(long challenge);
    }

    private abstract static class InternalGenerateChallengeCallback
            extends GenerateChallengeCallback {}

    /**
     * Request authentication of a crypto object. This call warms up the fingerprint hardware
     * and starts scanning for a fingerprint. It terminates when
@@ -514,19 +529,56 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
    }

    /**
     * Requests a pre-enrollment auth token to tie enrollment to the confirmation of
     * existing device credentials (e.g. pin/pattern/password).
     * Same as {@link #generateChallenge(GenerateChallengeCallback)}, except blocks until the
     * TEE/hardware operation is complete.
     * @return challenge generated in the TEE/hardware
     * @hide
     */
    @RequiresPermission(MANAGE_FINGERPRINT)
    public long generateChallengeBlocking() {
        final AtomicReference<Long> result = new AtomicReference<>();
        final CountDownLatch latch = new CountDownLatch(1);
        final GenerateChallengeCallback callback = new InternalGenerateChallengeCallback() {
            @Override
            public void onChallengeGenerated(long challenge) {
                result.set(challenge);
                latch.countDown();
            }
        };

        generateChallenge(callback);

        try {
            latch.await(1, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Slog.e(TAG, "Interrupted while generatingChallenge", e);
            e.printStackTrace();
        }

        return result.get();
    }


    /**
     * Generates a unique random challenge in the TEE. A typical use case is to have it wrapped in a
     * HardwareAuthenticationToken, minted by Gatekeeper upon PIN/Pattern/Password verification.
     * The HardwareAuthenticationToken can then be sent to the biometric HAL together with a
     * request to perform sensitive operation(s) (for example enroll), represented by the challenge.
     * Doing this ensures that a the sensitive operation cannot be performed unless the user has
     * entered confirmed PIN/Pattern/Password.
     *
     * @see com.android.server.locksettings.LockSettingsService
     *
     * @hide
     */
    @RequiresPermission(MANAGE_FINGERPRINT)
    public long preEnroll() {
        long result = 0;
    public void generateChallenge(GenerateChallengeCallback callback) {
        if (mService != null) try {
            result = mService.preEnroll(mToken);
            mGenerateChallengeCallback = callback;
            mService.generateChallenge(mToken, mServiceReceiver, mContext.getOpPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return result;
    }

    /**
@@ -534,14 +586,12 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
     * @hide
     */
    @RequiresPermission(MANAGE_FINGERPRINT)
    public int postEnroll() {
        int result = 0;
    public void revokeChallenge() {
        if (mService != null) try {
            result = mService.postEnroll(mToken);
            mService.revokeChallenge(mToken, mContext.getOpPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return result;
    }

    /**
@@ -558,7 +608,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
        if (mService != null) try {
            mRemovalCallback = callback;
            mRemovalFingerprint = fp;
            mService.remove(mToken, fp.getBiometricId(), fp.getGroupId(), userId, mServiceReceiver,
            mService.remove(mToken, fp.getBiometricId(), userId, mServiceReceiver,
                    mContext.getOpPackageName());
        } catch (RemoteException e) {
            Slog.w(TAG, "Remote exception in remove: ", e);
@@ -760,6 +810,12 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
                case MSG_REMOVED:
                    sendRemovedResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
                    break;
                case MSG_CHALLENGE_GENERATED:
                    sendChallengeGenerated((long) msg.obj /* challenge */);
                    break;
                default:
                    Slog.w(TAG, "Unknown message: " + msg.what);

            }
        }
    };
@@ -779,12 +835,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
            Slog.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
            return;
        }
        int groupId = fingerprint.getGroupId();
        int reqGroupId = mRemovalFingerprint.getGroupId();
        if (groupId != reqGroupId) {
            Slog.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
            return;
        }

        mRemovalCallback.onRemovalSucceeded(fingerprint, remaining);
    }
@@ -845,6 +895,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
        }
    }

    private void sendChallengeGenerated(long challenge) {
        if (mGenerateChallengeCallback == null) {
            Slog.e(TAG, "sendChallengeGenerated, callback null");
            return;
        }
        mGenerateChallengeCallback.onChallengeGenerated(challenge);
    }

    /**
     * @hide
     */
@@ -852,7 +910,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
        mContext = context;
        mService = service;
        if (mService == null) {
            Slog.v(TAG, "FingerprintManagerService was null");
            Slog.v(TAG, "FingerprintService was null");
        }
        mHandler = new MyHandler(context);
    }
@@ -998,6 +1056,17 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
        public void onRemoved(Fingerprint fp, int remaining) {
            mHandler.obtainMessage(MSG_REMOVED, remaining, 0, fp).sendToTarget();
        }

        @Override // binder call
        public void onChallengeGenerated(long challenge) {
            if (mGenerateChallengeCallback instanceof InternalGenerateChallengeCallback) {
                // Perform this on system_server thread, since the application's thread is
                // blocked waiting for the result
                mGenerateChallengeCallback.onChallengeGenerated(challenge);
            } else {
                mHandler.obtainMessage(MSG_CHALLENGE_GENERATED, challenge).sendToTarget();
            }
        }
    };

}
+4 −4
Original line number Diff line number Diff line
@@ -63,8 +63,8 @@ interface IFingerprintService {
    void cancelEnrollment(IBinder token);

    // Any errors resulting from this call will be returned to the listener
    void remove(IBinder token, int fingerId, int groupId, int userId,
            IFingerprintServiceReceiver receiver, String opPackageName);
    void remove(IBinder token, int fingerId, int userId, IFingerprintServiceReceiver receiver,
            String opPackageName);

    // Rename the fingerprint specified by fingerId and userId to the given name
    void rename(int fingerId, int userId, String name);
@@ -76,10 +76,10 @@ interface IFingerprintService {
    boolean isHardwareDetected(String opPackageName);

    // Get a pre-enrollment authentication token
    long preEnroll(IBinder token);
    void generateChallenge(IBinder token, IFingerprintServiceReceiver receiver, String opPackageName);

    // Finish an enrollment sequence and invalidate the authentication token
    int postEnroll(IBinder token);
    void revokeChallenge(IBinder token, String opPackageName);

    // Determine if a user has at least one enrolled fingerprint
    boolean hasEnrolledFingerprints(int userId, String opPackageName);
Loading