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

Commit 17775a65 authored by Roman Birg's avatar Roman Birg
Browse files

Fingerprint Wakeup: add some error handling; fix race conditions



- If the FingerprintManager reports that the HW is unavailable, it's
likely the service isn't up yet. Try to reinitialize the fingerprint
state when this happens.

- Fix a race condition when screen is turned off and fingerprint is
recognized but keyguard has not yet come back up.

- don't count Fingerprint sensor errors against failed user count

- Always stop authenticating when keyguard goes away.

- Make final vibrate when limit has been reached more obvious

Fingerprint Service changes:
- Don't remove wake client when removing listener. These should be
  handled separately.

- Remove wake client when wake is disabled

- remove finalize() call - the binderDied() interface accomplishes what
  we need to do the proper cleanup.

Ref: CYNGNOS-1125

Change-Id: Id22d8f4f409e3989d0a094eb4c4bab7da996937f
Signed-off-by: default avatarRoman Birg <roman@cyngn.com>
parent ccbaa26a
Loading
Loading
Loading
Loading
+16 −14
Original line number Diff line number Diff line
@@ -44,9 +44,7 @@ import android.os.BatteryManager;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.fingerprint.FingerprintManager;
@@ -57,7 +55,6 @@ import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseBooleanArray;

@@ -233,7 +230,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
                    handleFingerprintAcquired(msg.arg1);
                    break;
                case MSG_FINGERPRINT_PROCESSED:
                    handleFingerprintProcessed(msg.arg1);
                    handleFingerprintProcessed(msg.arg1 == 1, msg.arg2);
                    break;
                case MSG_FINGERPRINT_STATE_CHANGED:
                    handleFingerprintStateChanged(msg.arg1);
@@ -348,7 +345,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
        }
    }

    private void handleFingerprintProcessed(int fingerprintId) {
    private void handleFingerprintProcessed(boolean error, int fingerprintIdOrError) {
        if (!hasBootCompleted() || isSimPinSecure()) {
            return;
        }
@@ -364,32 +361,35 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
            Log.d(TAG, "Fingerprint disabled by DPM for userId: " + userId);
            return;
        }
        if (fingerprintId == 0) {
        if (error) {
            onFingerprintAttemptFailed(true, fingerprintIdOrError);
        } else if (fingerprintIdOrError == 0) {
            // not a valid fingerprint
            onFingerprintAttemptFailed();
            onFingerprintAttemptFailed(false, 0);
            return;
        }
        final ContentResolver res = mContext.getContentResolver();
        final List<Fingerprint> fingerprints = FingerprintUtils.getFingerprintsForUser(res, userId);
        boolean foundFingerprint = false;
        for (Fingerprint fingerprint : fingerprints) {
            if (fingerprint.getFingerId() == fingerprintId) {
            if (fingerprint.getFingerId() == fingerprintIdOrError) {
                foundFingerprint = true;
                onFingerprintRecognized(userId);
                break;
            }
        }
        if (!foundFingerprint) {
            onFingerprintAttemptFailed();
            onFingerprintAttemptFailed(true,
                    FingerprintManager.FINGERPRINT_ERROR_UNABLE_TO_PROCESS);
        }
    }

    private void onFingerprintAttemptFailed() {
        mFailedFingerprintAttempts++;
    private void onFingerprintAttemptFailed(boolean error, int errorCode) {
        if (!error) mFailedFingerprintAttempts++;
        for (int i = 0; i < mCallbacks.size(); i++) {
            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
            if (cb != null) {
                cb.onFingerprintAttemptFailed();
                cb.onFingerprintAttemptFailed(error, errorCode);
            }
        }
    }
@@ -568,7 +568,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
            new FingerprintManagerReceiver() {
        @Override
        public void onProcessed(int fingerprintId) {
            mHandler.obtainMessage(MSG_FINGERPRINT_PROCESSED, fingerprintId, 0).sendToTarget();
            mHandler.obtainMessage(MSG_FINGERPRINT_PROCESSED, 0 /* no error */, fingerprintId)
                    .sendToTarget();
        };

        @Override
@@ -583,7 +584,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {

        @Override
        public void onError(int error) {
            Log.w(TAG, "FingerprintManager reported error: " + error);
            mHandler.obtainMessage(MSG_FINGERPRINT_PROCESSED, 1 /* error */, error).sendToTarget();

        }
    };

+3 −1
Original line number Diff line number Diff line
@@ -195,8 +195,10 @@ public class KeyguardUpdateMonitorCallback {

    /**
     * Called when a fingerprint is recognized.
     * @param error true if fingerprint service reported an error
     * @param errorCode if {@code error} was true, this describes the error code
     */
    public void onFingerprintAttemptFailed() { }
    public void onFingerprintAttemptFailed(boolean error, int errorCode) { }

    /**
     * Called when fingerprint is acquired but not yet recognized
+62 −30
Original line number Diff line number Diff line
@@ -538,25 +538,49 @@ public class KeyguardViewMediator extends SystemUI {
                    Log.i(TAG, "onFingerprintRecognized(userId=" + userId + ")");
                }

                vibrateFingerprintSuccess();

                final boolean screenOn = mPM.isInteractive();

                if (!isShowingAndNotOccluded()) {
                    // fingerprint was recognized before keyguard has come back up fully
                    // cancel the pending keyguard call and wake up the device if necessary
                    if (DBG_FINGERPRINT) {
                        Log.w(TAG, "fingerprint recognized but kg not showing.");
                    }
                    cancelDoKeyguardLaterLocked();
                    if (!screenOn) {
                        mPM.wakeUp(SystemClock.uptimeMillis());
                    }
                    return;
                }

                mFingerprintWakeUnlock = !mPM.isInteractive();
                vibrateFingerprintSuccess();
                mFingerprintWakeUnlock = !screenOn;
                hideLocked();
            }
        }

        @Override
        public void onFingerprintAttemptFailed() {
        public void onFingerprintAttemptFailed(boolean error, int errorCode) {
            synchronized (KeyguardViewMediator.this) {
                mFingerAuthenticating = false;
                mStartFingerAuthOnIdle = false;

                if (!mPM.isInteractive()) { // mScreenOn isn't as reliable
                final boolean screenOn = mPM.isInteractive();

                if (error) {
                    switch (errorCode) {
                        case FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE:
                            // service may not be available.
                            setupFingerprint(screenOn);
                            return;
                        default:
                            Log.e(TAG, "FingerprintManager reported unhandled error: " + errorCode);
                            return;
                    }
                }

                if (!screenOn) { // mScreenOn isn't as reliable
                    if (DBG_FINGERPRINT) {
                        Log.i(TAG, "onFingerprintAttemptFailed() and screen is off");
                    }
@@ -606,39 +630,20 @@ public class KeyguardViewMediator extends SystemUI {
                    mContext.getSystemService(Context.VIBRATOR_SERVICE);
            if (v != null) {
                final long[] pattern = graveWarning
                        ? new long[]{0, 50, 100, 50, 100, 50}
                        ? new long[]{0, 75, 100, 75, 100, 75, 100, 75}
                        : new long[]{0, 50, 100, 50};
                v.vibrate(pattern, -1, VIBRATION_ATTRIBUTES);
            }
        }

        @Override
        public void onScreenTurnedOff(int why) {
            if (isFingerprintActive()) {
                synchronized (KeyguardViewMediator.this) {
                    mHandler.removeMessages(KEYGUARD_FINGERPRINT_AUTH);
                    mHandler.obtainMessage(KEYGUARD_FINGERPRINT_AUTH, 0, 0).sendToTarget();
                    mUpdateMonitor.clearFingerprintRecognized();
                    mFingerprintWakeUnlock = false;
                    mFingerTurnedScreenOn = false;
                    mStartFingerAuthOnIdle = false;
                    mFingerAuthenticating = false;
                    FingerprintManager fpm = (FingerprintManager)
                            mContext.getSystemService(Context.FINGERPRINT_SERVICE);
                    if (fpm != null) {
                        fpm.setWakeup(true);
                    }
                    mUpdateMonitor.setFingerprintListening(true);
                }
            }
        private void setupFingerprint(boolean screenOn) {
            if (!isFingerprintActive()) {
                return;
            }

        @Override
        public void onScreenTurnedOn() {
            if (isFingerprintActive()) {
                synchronized (KeyguardViewMediator.this) {
            FingerprintManager fpm = (FingerprintManager)
                    mContext.getSystemService(Context.FINGERPRINT_SERVICE);
            if (screenOn) {
                synchronized (KeyguardViewMediator.this) {
                    if (!mPM.isInteractive()) {
                        // if keyguard was restarted while screen is off we get in this false state
                        if (DBG_FINGERPRINT) {
@@ -681,7 +686,31 @@ public class KeyguardViewMediator extends SystemUI {
                        }
                    }
                }
            } else {
                synchronized (KeyguardViewMediator.this) {
                    mUpdateMonitor.clearFingerprintRecognized();
                    mHandler.removeMessages(KEYGUARD_FINGERPRINT_AUTH);
                    mHandler.sendMessage(mHandler.obtainMessage(KEYGUARD_FINGERPRINT_AUTH, 0, 0));
                    mUpdateMonitor.setFingerprintListening(true);
                    mFingerprintWakeUnlock = false;
                    mFingerTurnedScreenOn = false;
                    mStartFingerAuthOnIdle = false;
                    mFingerAuthenticating = false;
                    if (fpm != null) {
                        fpm.setWakeup(true);
                    }
                }
            }
        }

        @Override
        public void onScreenTurnedOff(int why) {
            setupFingerprint(false);
        }

        @Override
        public void onScreenTurnedOn() {
            setupFingerprint(true);
            synchronized (KeyguardViewMediator.this) {
                if (mSkipToBouncer) {
                    mSkipToBouncer = false;
@@ -697,6 +726,9 @@ public class KeyguardViewMediator extends SystemUI {
            super.onKeyguardVisibilityChanged(showing);
            if (isFingerprintActive()) {
                synchronized (KeyguardViewMediator.this) {
                    if (!showing) {
                        stopAuthenticatingFingerprint();
                    }
                    mUpdateMonitor.setFingerprintListening(showing);
                }
            }
+2 −2
Original line number Diff line number Diff line
@@ -2126,8 +2126,8 @@ public class NotificationPanelView extends PanelView implements

    private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
        @Override
        public void onFingerprintAttemptFailed() {
            if (!mStatusBar.isBouncerShowing() && mStatusBar.isScreenOnFromKeyguard()) {
        public void onFingerprintAttemptFailed(boolean error, int errorCode) {
            if (!error && !mStatusBar.isBouncerShowing() && mStatusBar.isScreenOnFromKeyguard()) {
                NotificationPanelView.super.startHintAnimation(true /* fingerprintHint */);
            }
        }
+2 −2
Original line number Diff line number Diff line
@@ -140,8 +140,8 @@ public class UnlockMethodCache {
        }

        @Override
        public void onFingerprintAttemptFailed() {
            update(true /* updateAlways */);
        public void onFingerprintAttemptFailed(boolean error, int errorCode) {
            update(!error);
        }

        @Override
Loading