• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2014 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.app.Service;
20 import android.content.ContentResolver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.os.Handler;
24 import android.os.IBinder;
25 import android.os.PowerManager;
26 import android.os.RemoteException;
27 import android.provider.Settings;
28 import android.service.fingerprint.FingerprintManager;
29 import android.util.ArrayMap;
30 import android.util.Slog;
31 
32 import com.android.server.SystemService;
33 
34 import android.service.fingerprint.FingerprintUtils;
35 import android.service.fingerprint.IFingerprintService;
36 import android.service.fingerprint.IFingerprintServiceReceiver;
37 
38 import java.io.PrintWriter;
39 import java.lang.ref.WeakReference;
40 import java.util.HashMap;
41 import java.util.Map.Entry;
42 import java.util.Set;
43 
44 /**
45  * A service to manage multiple clients that want to access the fingerprint HAL API.
46  * The service is responsible for maintaining a list of clients and dispatching all
47  * fingerprint -related events.
48  *
49  * @hide
50  */
51 public class FingerprintService extends SystemService {
52     private final String TAG = "FingerprintService";
53     private static final boolean DEBUG = true;
54     private ArrayMap<IBinder, ClientData> mClients = new ArrayMap<IBinder, ClientData>();
55 
56     private static final int MSG_NOTIFY = 10;
57 
58     Handler mHandler = new Handler() {
59         public void handleMessage(android.os.Message msg) {
60             switch (msg.what) {
61                 case MSG_NOTIFY:
62                     handleNotify(msg.arg1, msg.arg2, (Integer) msg.obj);
63                     break;
64 
65                 default:
66                     Slog.w(TAG, "Unknown message:" + msg.what);
67             }
68         }
69     };
70     private Context mContext;
71 
72     private static final int STATE_IDLE = 0;
73     private static final int STATE_LISTENING = 1;
74     private static final int STATE_ENROLLING = 2;
75     private static final int STATE_REMOVING = 3;
76     private static final long MS_PER_SEC = 1000;
77     public static final String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
78     public static final String ENROLL_FINGERPRINT = "android.permission.ENROLL_FINGERPRINT";
79 
80     private static final class ClientData {
81         public IFingerprintServiceReceiver receiver;
82         int state;
83         int userId;
84         public TokenWatcher tokenWatcher;
getToken()85         IBinder getToken() { return tokenWatcher.getToken(); }
86     }
87 
88     private class TokenWatcher implements IBinder.DeathRecipient {
89         WeakReference<IBinder> token;
90 
TokenWatcher(IBinder token)91         TokenWatcher(IBinder token) {
92             this.token = new WeakReference<IBinder>(token);
93         }
94 
getToken()95         IBinder getToken() { return token.get(); }
binderDied()96         public void binderDied() {
97             mClients.remove(token);
98             this.token = null;
99         }
100 
finalize()101         protected void finalize() throws Throwable {
102             try {
103                 if (token != null) {
104                     if (DEBUG) Slog.w(TAG, "removing leaked reference: " + token);
105                     mClients.remove(token);
106                 }
107             } finally {
108                 super.finalize();
109             }
110         }
111     }
112 
FingerprintService(Context context)113     public FingerprintService(Context context) {
114         super(context);
115         mContext = context;
116         nativeInit(this);
117     }
118 
119     // TODO: Move these into separate process
120     // JNI methods to communicate from FingerprintManagerService to HAL
nativeEnroll(int timeout)121     native int nativeEnroll(int timeout);
nativeEnrollCancel()122     native int nativeEnrollCancel();
nativeRemove(int fingerprintId)123     native int nativeRemove(int fingerprintId);
nativeOpenHal()124     native int nativeOpenHal();
nativeCloseHal()125     native int nativeCloseHal();
nativeInit(FingerprintService service)126     native void nativeInit(FingerprintService service);
127 
128     // JNI methods for communicating from HAL to clients
notify(int msg, int arg1, int arg2)129     void notify(int msg, int arg1, int arg2) {
130         mHandler.obtainMessage(MSG_NOTIFY, msg, arg1, arg2).sendToTarget();
131     }
132 
handleNotify(int msg, int arg1, int arg2)133     void handleNotify(int msg, int arg1, int arg2) {
134         Slog.v(TAG, "handleNotify(msg=" + msg + ", arg1=" + arg1 + ", arg2=" + arg2 + ")");
135         for (int i = 0; i < mClients.size(); i++) {
136             ClientData clientData = mClients.valueAt(i);
137             if (clientData == null || clientData.receiver == null) {
138                 if (DEBUG) Slog.v(TAG, "clientData at " + i + " is invalid!!");
139                 continue;
140             }
141             switch (msg) {
142                 case FingerprintManager.FINGERPRINT_ERROR: {
143                     final int error = arg1;
144                     try {
145                         clientData.receiver.onError(error);
146                     } catch (RemoteException e) {
147                         Slog.e(TAG, "can't send message to client. Did it die?", e);
148                         mClients.remove(mClients.keyAt(i));
149                     }
150                 }
151                 break;
152                 case FingerprintManager.FINGERPRINT_ACQUIRED: {
153                     final int acquireInfo = arg1;
154                     try {
155                         clientData.receiver.onAcquired(acquireInfo);
156                     } catch (RemoteException e) {
157                         Slog.e(TAG, "can't send message to client. Did it die?", e);
158                         mClients.remove(mClients.keyAt(i));
159                     }
160                     break;
161                 }
162                 case FingerprintManager.FINGERPRINT_PROCESSED: {
163                     final int fingerId = arg1;
164                     try {
165                         clientData.receiver.onProcessed(fingerId);
166                     } catch (RemoteException e) {
167                         Slog.e(TAG, "can't send message to client. Did it die?", e);
168                         mClients.remove(mClients.keyAt(i));
169                     }
170                     break;
171                 }
172                 case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
173                     final int fingerId = arg1;
174                     final int remaining = arg2;
175                     if (clientData.state == STATE_ENROLLING) {
176                         // Only send enroll updates to clients that are actually enrolling
177                         try {
178                             clientData.receiver.onEnrollResult(fingerId, remaining);
179                         } catch (RemoteException e) {
180                             Slog.e(TAG, "can't send message to client. Did it die?", e);
181                             mClients.remove(mClients.keyAt(i));
182                         }
183                         // Update the database with new finger id.
184                         // TODO: move to client code (Settings)
185                         if (remaining == 0) {
186                             FingerprintUtils.addFingerprintIdForUser(fingerId,
187                                     mContext.getContentResolver(), clientData.userId);
188                             clientData.state = STATE_IDLE; // Nothing left to do
189                         }
190                     } else {
191                         if (DEBUG) Slog.w(TAG, "Client not enrolling");
192                         break;
193                     }
194                     break;
195                 }
196                 case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: {
197                     int fingerId = arg1;
198                     if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL");
199                     FingerprintUtils.removeFingerprintIdForUser(fingerId,
200                             mContext.getContentResolver(), clientData.userId);
201                     if (clientData.receiver != null) {
202                         try {
203                             clientData.receiver.onRemoved(fingerId);
204                         } catch (RemoteException e) {
205                             Slog.e(TAG, "can't send message to client. Did it die?", e);
206                             mClients.remove(mClients.keyAt(i));
207                         }
208                     }
209                     clientData.state = STATE_LISTENING;
210                 }
211                 break;
212             }
213         }
214     }
215 
startEnroll(IBinder token, long timeout, int userId)216     void startEnroll(IBinder token, long timeout, int userId) {
217         ClientData clientData = mClients.get(token);
218         if (clientData != null) {
219             if (clientData.userId != userId) throw new IllegalStateException("Bad user");
220             clientData.state = STATE_ENROLLING;
221             nativeEnroll((int) (timeout / MS_PER_SEC));
222         } else {
223             Slog.w(TAG, "enroll(): No listener registered");
224         }
225     }
226 
startEnrollCancel(IBinder token, int userId)227     void startEnrollCancel(IBinder token, int userId) {
228         ClientData clientData = mClients.get(token);
229         if (clientData != null) {
230             if (clientData.userId != userId) throw new IllegalStateException("Bad user");
231             clientData.state = STATE_LISTENING;
232             nativeEnrollCancel();
233         } else {
234             Slog.w(TAG, "enrollCancel(): No listener registered");
235         }
236     }
237 
238     // Remove all fingerprints for the given user.
startRemove(IBinder token, int fingerId, int userId)239     void startRemove(IBinder token, int fingerId, int userId) {
240         ClientData clientData = mClients.get(token);
241         if (clientData != null) {
242             if (clientData.userId != userId) throw new IllegalStateException("Bad user");
243             clientData.state = STATE_REMOVING;
244             // The fingerprint id will be removed when we get confirmation from the HAL
245             int result = nativeRemove(fingerId);
246             if (result != 0) {
247                 Slog.w(TAG, "Error removing fingerprint with id = " + fingerId);
248             }
249         } else {
250             Slog.w(TAG, "remove(" + token + "): No listener registered");
251         }
252     }
253 
addListener(IBinder token, IFingerprintServiceReceiver receiver, int userId)254     void addListener(IBinder token, IFingerprintServiceReceiver receiver, int userId) {
255         if (DEBUG) Slog.v(TAG, "startListening(" + receiver + ")");
256         if (mClients.get(token) == null) {
257             ClientData clientData = new ClientData();
258             clientData.state = STATE_LISTENING;
259             clientData.receiver = receiver;
260             clientData.userId = userId;
261             clientData.tokenWatcher = new TokenWatcher(token);
262             try {
263                 token.linkToDeath(clientData.tokenWatcher, 0);
264                 mClients.put(token, clientData);
265             } catch (RemoteException e) {
266                 Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
267             }
268         } else {
269             if (DEBUG) Slog.v(TAG, "listener already registered for " + token);
270         }
271     }
272 
removeListener(IBinder token, int userId)273     void removeListener(IBinder token, int userId) {
274         if (DEBUG) Slog.v(TAG, "stopListening(" + token + ")");
275         ClientData clientData = mClients.get(token);
276         if (clientData != null) {
277             token.unlinkToDeath(clientData.tokenWatcher, 0);
278             mClients.remove(token);
279         } else {
280             if (DEBUG) Slog.v(TAG, "listener not registered: " + token);
281         }
282         mClients.remove(token);
283     }
284 
checkPermission(String permisison)285     void checkPermission(String permisison) {
286         // TODO
287     }
288 
289     private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
290         @Override // Binder call
enroll(IBinder token, long timeout, int userId)291         public void enroll(IBinder token, long timeout, int userId) {
292             checkPermission(ENROLL_FINGERPRINT);
293             startEnroll(token, timeout, userId);
294         }
295 
296         @Override // Binder call
enrollCancel(IBinder token,int userId)297         public void enrollCancel(IBinder token,int userId) {
298             checkPermission(ENROLL_FINGERPRINT);
299             startEnrollCancel(token, userId);
300         }
301 
302         @Override // Binder call
remove(IBinder token, int fingerprintId, int userId)303         public void remove(IBinder token, int fingerprintId, int userId) {
304             checkPermission(ENROLL_FINGERPRINT); // TODO: Maybe have another permission
305             startRemove(token, fingerprintId, userId);
306         }
307 
308         @Override // Binder call
startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId)309         public void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId)
310         {
311             checkPermission(USE_FINGERPRINT);
312             addListener(token, receiver, userId);
313         }
314 
315         @Override // Binder call
stopListening(IBinder token, int userId)316         public void stopListening(IBinder token, int userId) {
317             checkPermission(USE_FINGERPRINT);
318             removeListener(token, userId);
319         }
320     }
321 
322     @Override
onStart()323     public void onStart() {
324        publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
325        nativeOpenHal();
326     }
327 
328 }
329