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; 85 IBinder getToken() { return tokenWatcher.getToken(); } 86 } 87 88 private class TokenWatcher implements IBinder.DeathRecipient { 89 WeakReference<IBinder> token; 90 91 TokenWatcher(IBinder token) { 92 this.token = new WeakReference<IBinder>(token); 93 } 94 95 IBinder getToken() { return token.get(); } 96 public void binderDied() { 97 mClients.remove(token); 98 this.token = null; 99 } 100 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 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 121 native int nativeEnroll(int timeout); 122 native int nativeEnrollCancel(); 123 native int nativeRemove(int fingerprintId); 124 native int nativeOpenHal(); 125 native int nativeCloseHal(); 126 native void nativeInit(FingerprintService service); 127 128 // JNI methods for communicating from HAL to clients 129 void notify(int msg, int arg1, int arg2) { 130 mHandler.obtainMessage(MSG_NOTIFY, msg, arg1, arg2).sendToTarget(); 131 } 132 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 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 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. 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 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 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 285 void checkPermission(String permisison) { 286 // TODO 287 } 288 289 private final class FingerprintServiceWrapper extends IFingerprintService.Stub { 290 @Override // Binder call 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 297 public void enrollCancel(IBinder token,int userId) { 298 checkPermission(ENROLL_FINGERPRINT); 299 startEnrollCancel(token, userId); 300 } 301 302 @Override // Binder call 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 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 316 public void stopListening(IBinder token, int userId) { 317 checkPermission(USE_FINGERPRINT); 318 removeListener(token, userId); 319 } 320 } 321 322 @Override 323 public void onStart() { 324 publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper()); 325 nativeOpenHal(); 326 } 327 328 } 329