Home | History | Annotate | Download | only in fingerprint
      1 /**
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.fingerprint;
     18 
     19 import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
     20 import com.android.internal.logging.MetricsLogger;
     21 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
     22 
     23 import android.content.Context;
     24 import android.hardware.fingerprint.Fingerprint;
     25 import android.hardware.fingerprint.FingerprintManager;
     26 import android.hardware.fingerprint.IFingerprintServiceReceiver;
     27 import android.os.IBinder;
     28 import android.os.RemoteException;
     29 import android.util.Slog;
     30 
     31 /**
     32  * A class to keep track of the authentication state for a given client.
     33  */
     34 public abstract class AuthenticationClient extends ClientMonitor {
     35     private long mOpId;
     36 
     37     public abstract int handleFailedAttempt();
     38     public abstract void resetFailedAttempts();
     39 
     40     public static final int LOCKOUT_NONE = 0;
     41     public static final int LOCKOUT_TIMED = 1;
     42     public static final int LOCKOUT_PERMANENT = 2;
     43 
     44     public AuthenticationClient(Context context, long halDeviceId, IBinder token,
     45             IFingerprintServiceReceiver receiver, int targetUserId, int groupId, long opId,
     46             boolean restricted, String owner) {
     47         super(context, halDeviceId, token, receiver, targetUserId, groupId, restricted, owner);
     48         mOpId = opId;
     49     }
     50 
     51     @Override
     52     public boolean onAuthenticated(int fingerId, int groupId) {
     53         boolean result = false;
     54         boolean authenticated = fingerId != 0;
     55 
     56         IFingerprintServiceReceiver receiver = getReceiver();
     57         if (receiver != null) {
     58             try {
     59                 MetricsLogger.action(getContext(), MetricsEvent.ACTION_FINGERPRINT_AUTH,
     60                         authenticated);
     61                 if (!authenticated) {
     62                     receiver.onAuthenticationFailed(getHalDeviceId());
     63                 } else {
     64                     if (DEBUG) {
     65                         Slog.v(TAG, "onAuthenticated(owner=" + getOwnerString()
     66                                 + ", id=" + fingerId + ", gp=" + groupId + ")");
     67                     }
     68                     Fingerprint fp = !getIsRestricted()
     69                             ? new Fingerprint("" /* TODO */, groupId, fingerId, getHalDeviceId())
     70                             : null;
     71                     receiver.onAuthenticationSucceeded(getHalDeviceId(), fp, getTargetUserId());
     72                 }
     73             } catch (RemoteException e) {
     74                 Slog.w(TAG, "Failed to notify Authenticated:", e);
     75                 result = true; // client failed
     76             }
     77         } else {
     78             result = true; // client not listening
     79         }
     80         if (!authenticated) {
     81             if (receiver != null) {
     82                 vibrateError();
     83             }
     84             // allow system-defined limit of number of attempts before giving up
     85             int lockoutMode =  handleFailedAttempt();
     86             if (lockoutMode != LOCKOUT_NONE) {
     87                 try {
     88                     Slog.w(TAG, "Forcing lockout (fp driver code should do this!), mode(" +
     89                             lockoutMode + ")");
     90                     stop(false);
     91                     int errorCode = lockoutMode == LOCKOUT_TIMED ?
     92                             FingerprintManager.FINGERPRINT_ERROR_LOCKOUT :
     93                             FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
     94                     receiver.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */);
     95                 } catch (RemoteException e) {
     96                     Slog.w(TAG, "Failed to notify lockout:", e);
     97                 }
     98             }
     99             result |= lockoutMode != LOCKOUT_NONE; // in a lockout mode
    100         } else {
    101             if (receiver != null) {
    102                 vibrateSuccess();
    103             }
    104             result |= true; // we have a valid fingerprint, done
    105             resetFailedAttempts();
    106         }
    107         return result;
    108     }
    109 
    110     /**
    111      * Start authentication
    112      */
    113     @Override
    114     public int start() {
    115         IBiometricsFingerprint daemon = getFingerprintDaemon();
    116         if (daemon == null) {
    117             Slog.w(TAG, "start authentication: no fingerprint HAL!");
    118             return ERROR_ESRCH;
    119         }
    120         try {
    121             final int result = daemon.authenticate(mOpId, getGroupId());
    122             if (result != 0) {
    123                 Slog.w(TAG, "startAuthentication failed, result=" + result);
    124                 MetricsLogger.histogram(getContext(), "fingeprintd_auth_start_error", result);
    125                 onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
    126                 return result;
    127             }
    128             if (DEBUG) Slog.w(TAG, "client " + getOwnerString() + " is authenticating...");
    129         } catch (RemoteException e) {
    130             Slog.e(TAG, "startAuthentication failed", e);
    131             return ERROR_ESRCH;
    132         }
    133         return 0; // success
    134     }
    135 
    136     @Override
    137     public int stop(boolean initiatedByClient) {
    138         if (mAlreadyCancelled) {
    139             Slog.w(TAG, "stopAuthentication: already cancelled!");
    140             return 0;
    141         }
    142         IBiometricsFingerprint daemon = getFingerprintDaemon();
    143         if (daemon == null) {
    144             Slog.w(TAG, "stopAuthentication: no fingerprint HAL!");
    145             return ERROR_ESRCH;
    146         }
    147         try {
    148             final int result = daemon.cancel();
    149             if (result != 0) {
    150                 Slog.w(TAG, "stopAuthentication failed, result=" + result);
    151                 return result;
    152             }
    153             if (DEBUG) Slog.w(TAG, "client " + getOwnerString() + " is no longer authenticating");
    154         } catch (RemoteException e) {
    155             Slog.e(TAG, "stopAuthentication failed", e);
    156             return ERROR_ESRCH;
    157         }
    158         mAlreadyCancelled = true;
    159         return 0; // success
    160     }
    161 
    162     @Override
    163     public boolean onEnrollResult(int fingerId, int groupId, int remaining) {
    164         if (DEBUG) Slog.w(TAG, "onEnrollResult() called for authenticate!");
    165         return true; // Invalid for Authenticate
    166     }
    167 
    168     @Override
    169     public boolean onRemoved(int fingerId, int groupId, int remaining) {
    170         if (DEBUG) Slog.w(TAG, "onRemoved() called for authenticate!");
    171         return true; // Invalid for Authenticate
    172     }
    173 
    174     @Override
    175     public boolean onEnumerationResult(int fingerId, int groupId, int remaining) {
    176         if (DEBUG) Slog.w(TAG, "onEnumerationResult() called for authenticate!");
    177         return true; // Invalid for Authenticate
    178     }
    179 }
    180