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.Manifest;
     20 import android.content.Context;
     21 import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
     22 import android.hardware.fingerprint.FingerprintManager;
     23 import android.hardware.fingerprint.IFingerprintServiceReceiver;
     24 import android.os.IBinder;
     25 import android.os.RemoteException;
     26 import android.os.VibrationEffect;
     27 import android.os.Vibrator;
     28 import android.util.Slog;
     29 
     30 import java.util.NoSuchElementException;
     31 
     32 /**
     33  * Abstract base class for keeping track and dispatching events from fingerprint HAL to the
     34  * the current client.  Subclasses are responsible for coordinating the interaction with
     35  * fingerprint HAL for the specific action (e.g. authenticate, enroll, enumerate, etc.).
     36  */
     37 public abstract class ClientMonitor implements IBinder.DeathRecipient {
     38     protected static final String TAG = FingerprintService.TAG; // TODO: get specific name
     39     protected static final int ERROR_ESRCH = 3; // Likely fingerprint HAL is dead. See errno.h.
     40     protected static final boolean DEBUG = FingerprintService.DEBUG;
     41     private static final long[] DEFAULT_SUCCESS_VIBRATION_PATTERN = new long[] {0, 30};
     42     private final Context mContext;
     43     private final long mHalDeviceId;
     44     private final int mTargetUserId;
     45     private final int mGroupId;
     46     // True if client does not have MANAGE_FINGERPRINT permission
     47     private final boolean mIsRestricted;
     48     private final String mOwner;
     49     private final VibrationEffect mSuccessVibrationEffect;
     50     private final VibrationEffect mErrorVibrationEffect;
     51     private IBinder mToken;
     52     private IFingerprintServiceReceiver mReceiver;
     53     protected boolean mAlreadyCancelled;
     54 
     55     /**
     56      * @param context context of FingerprintService
     57      * @param halDeviceId the HAL device ID of the associated fingerprint hardware
     58      * @param token a unique token for the client
     59      * @param receiver recipient of related events (e.g. authentication)
     60      * @param userId target user id for operation
     61      * @param groupId groupId for the fingerprint set
     62      * @param restricted whether or not client has the {@link Manifest#MANAGE_FINGERPRINT}
     63      * permission
     64      * @param owner name of the client that owns this
     65      */
     66     public ClientMonitor(Context context, long halDeviceId, IBinder token,
     67             IFingerprintServiceReceiver receiver, int userId, int groupId,boolean restricted,
     68             String owner) {
     69         mContext = context;
     70         mHalDeviceId = halDeviceId;
     71         mToken = token;
     72         mReceiver = receiver;
     73         mTargetUserId = userId;
     74         mGroupId = groupId;
     75         mIsRestricted = restricted;
     76         mOwner = owner;
     77         mSuccessVibrationEffect = getSuccessVibrationEffect(context);
     78         mErrorVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
     79         try {
     80             if (token != null) {
     81                 token.linkToDeath(this, 0);
     82             }
     83         } catch (RemoteException e) {
     84             Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
     85         }
     86     }
     87 
     88     /**
     89      * Contacts fingerprint HAL to start the client.
     90      * @return 0 on success, errno from driver on failure
     91      */
     92     public abstract int start();
     93 
     94     /**
     95      * Contacts fingerprint HAL to stop the client.
     96      * @param initiatedByClient whether the operation is at the request of a client
     97      */
     98     public abstract int stop(boolean initiatedByClient);
     99 
    100     /**
    101      * Method to explicitly poke powermanager on events
    102      */
    103     public abstract void notifyUserActivity();
    104 
    105     /**
    106      * Gets the fingerprint daemon from the cached state in the container class.
    107      */
    108     public abstract IBiometricsFingerprint getFingerprintDaemon();
    109 
    110     // Event callbacks from driver. Inappropriate calls is flagged/logged by the
    111     // respective client (e.g. enrolling shouldn't get authenticate events).
    112     // All of these return 'true' if the operation is completed and it's ok to move
    113     // to the next client (e.g. authentication accepts or rejects a fingerprint).
    114     public abstract boolean onEnrollResult(int fingerId, int groupId, int rem);
    115     public abstract boolean onAuthenticated(int fingerId, int groupId);
    116     public abstract boolean onRemoved(int fingerId, int groupId, int remaining);
    117     public abstract boolean onEnumerationResult(int fingerId, int groupId, int remaining);
    118 
    119     /**
    120      * Called when we get notification from fingerprint HAL that an image has been acquired.
    121      * Common to authenticate and enroll.
    122      * @param acquiredInfo info about the current image acquisition
    123      * @return true if client should be removed
    124      */
    125     public boolean onAcquired(int acquiredInfo, int vendorCode) {
    126         if (mReceiver == null)
    127             return true; // client not connected
    128         try {
    129             mReceiver.onAcquired(getHalDeviceId(), acquiredInfo, vendorCode);
    130             return false; // acquisition continues...
    131         } catch (RemoteException e) {
    132             Slog.w(TAG, "Failed to invoke sendAcquired:", e);
    133             return true; // client failed
    134         } finally {
    135             // Good scans will keep the device awake
    136             if (acquiredInfo == FingerprintManager.FINGERPRINT_ACQUIRED_GOOD) {
    137                 notifyUserActivity();
    138             }
    139         }
    140     }
    141 
    142     /**
    143      * Called when we get notification from fingerprint HAL that an error has occurred with the
    144      * current operation. Common to authenticate, enroll, enumerate and remove.
    145      * @param error
    146      * @return true if client should be removed
    147      */
    148     public boolean onError(int error, int vendorCode) {
    149         if (mReceiver != null) {
    150             try {
    151                 mReceiver.onError(getHalDeviceId(), error, vendorCode);
    152             } catch (RemoteException e) {
    153                 Slog.w(TAG, "Failed to invoke sendError:", e);
    154             }
    155         }
    156         return true; // errors always remove current client
    157     }
    158 
    159     public void destroy() {
    160         if (mToken != null) {
    161             try {
    162                 mToken.unlinkToDeath(this, 0);
    163             } catch (NoSuchElementException e) {
    164                 // TODO: remove when duplicate call bug is found
    165                 Slog.e(TAG, "destroy(): " + this + ":", new Exception("here"));
    166             }
    167             mToken = null;
    168         }
    169         mReceiver = null;
    170     }
    171 
    172     @Override
    173     public void binderDied() {
    174         mToken = null;
    175         mReceiver = null;
    176         onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
    177     }
    178 
    179     @Override
    180     protected void finalize() throws Throwable {
    181         try {
    182             if (mToken != null) {
    183                 if (DEBUG) Slog.w(TAG, "removing leaked reference: " + mToken);
    184                 onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
    185             }
    186         } finally {
    187             super.finalize();
    188         }
    189     }
    190 
    191     public final Context getContext() {
    192         return mContext;
    193     }
    194 
    195     public final long getHalDeviceId() {
    196         return mHalDeviceId;
    197     }
    198 
    199     public final String getOwnerString() {
    200         return mOwner;
    201     }
    202 
    203     public final IFingerprintServiceReceiver getReceiver() {
    204         return mReceiver;
    205     }
    206 
    207     public final boolean getIsRestricted() {
    208         return mIsRestricted;
    209     }
    210 
    211     public final int getTargetUserId() {
    212         return mTargetUserId;
    213     }
    214 
    215     public final int getGroupId() {
    216         return mGroupId;
    217     }
    218 
    219     public final IBinder getToken() {
    220         return mToken;
    221     }
    222 
    223     public final void vibrateSuccess() {
    224         Vibrator vibrator = mContext.getSystemService(Vibrator.class);
    225         if (vibrator != null) {
    226             vibrator.vibrate(mSuccessVibrationEffect);
    227         }
    228     }
    229 
    230     public final void vibrateError() {
    231         Vibrator vibrator = mContext.getSystemService(Vibrator.class);
    232         if (vibrator != null) {
    233             vibrator.vibrate(mErrorVibrationEffect);
    234         }
    235     }
    236 
    237     private static VibrationEffect getSuccessVibrationEffect(Context ctx) {
    238         int[] arr = ctx.getResources().getIntArray(
    239                 com.android.internal.R.array.config_longPressVibePattern);
    240         final long[] vibePattern;
    241         if (arr == null || arr.length == 0) {
    242             vibePattern = DEFAULT_SUCCESS_VIBRATION_PATTERN;
    243         } else {
    244             vibePattern = new long[arr.length];
    245             for (int i = 0; i < arr.length; i++) {
    246                 vibePattern[i] = arr[i];
    247             }
    248         }
    249         if (vibePattern.length == 1) {
    250             return VibrationEffect.createOneShot(
    251                     vibePattern[0], VibrationEffect.DEFAULT_AMPLITUDE);
    252         } else {
    253             return VibrationEffect.createWaveform(vibePattern, -1);
    254         }
    255     }
    256 
    257 }
    258