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      */
ClientMonitor(Context context, long halDeviceId, IBinder token, IFingerprintServiceReceiver receiver, int userId, int groupId,boolean restricted, String owner)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      */
start()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      */
stop(boolean initiatedByClient)104     public abstract int stop(boolean initiatedByClient);
105 
106     /**
107      * Method to explicitly poke powermanager on events
108      */
notifyUserActivity()109     public abstract void notifyUserActivity();
110 
111     /**
112      * Gets the fingerprint daemon from the cached state in the container class.
113      */
getFingerprintDaemon()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).
onEnrollResult(int fingerId, int groupId, int rem)120     public abstract boolean onEnrollResult(int fingerId, int groupId, int rem);
onAuthenticated(int fingerId, int groupId)121     public abstract boolean onAuthenticated(int fingerId, int groupId);
onRemoved(int fingerId, int groupId, int remaining)122     public abstract boolean onRemoved(int fingerId, int groupId, int remaining);
onEnumerationResult(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      */
onAcquired(int acquiredInfo, int vendorCode)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      */
onError(int error, int vendorCode)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 
destroy()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
binderDied()179     public void binderDied() {
180         mToken = null;
181         mReceiver = null;
182         onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
183     }
184 
185     @Override
finalize()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 
getContext()197     public final Context getContext() {
198         return mContext;
199     }
200 
getHalDeviceId()201     public final long getHalDeviceId() {
202         return mHalDeviceId;
203     }
204 
getOwnerString()205     public final String getOwnerString() {
206         return mOwner;
207     }
208 
getReceiver()209     public final IFingerprintServiceReceiver getReceiver() {
210         return mReceiver;
211     }
212 
getIsRestricted()213     public final boolean getIsRestricted() {
214         return mIsRestricted;
215     }
216 
getTargetUserId()217     public final int getTargetUserId() {
218         return mTargetUserId;
219     }
220 
getGroupId()221     public final int getGroupId() {
222         return mGroupId;
223     }
224 
getToken()225     public final IBinder getToken() {
226         return mToken;
227     }
228 
vibrateSuccess()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 
vibrateError()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