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