Android M 指纹框架
几个路径:
/frameworks/base/services/core/java/com/android/server/fingerprint/
/frameworks/base/core/java/android/hardware/fingerprint/
/system/core/fingerprintd/
/hardware/libhardware/include/hardware/fingerprint.h
/hardware/libhardware/modules/fingerprint/fingerprint.c
====================================================
/frameworks/base/services/core/java/com/android/server/fingerprint/
-------------------------------------------------------------------------------------------
FingerprintService.java
/** * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.android.server.fingerprint;import android.app.ActivityManager;import android.app.ActivityManagerNative;import android.app.AppOpsManager;import android.app.IUserSwitchObserver;import android.content.ContentResolver;import android.content.Context;import android.content.pm.PackageManager;import android.content.pm.UserInfo;import android.os.Binder;import android.os.Environment;import android.os.Handler;import android.os.IBinder;import android.os.IRemoteCallback;import android.os.Looper;import android.os.MessageQueue;import android.os.PowerManager;import android.os.RemoteException;import android.os.SELinux;import android.os.ServiceManager;import android.os.SystemClock;import android.os.UserHandle;import android.os.UserManager;import android.util.Slog;import com.android.server.SystemService;import android.hardware.fingerprint.Fingerprint;import android.hardware.fingerprint.FingerprintManager;import android.hardware.fingerprint.IFingerprintService;import android.hardware.fingerprint.IFingerprintDaemon;import android.hardware.fingerprint.IFingerprintDaemonCallback;import android.hardware.fingerprint.IFingerprintServiceReceiver;import static android.Manifest.permission.MANAGE_FINGERPRINT;import static android.Manifest.permission.USE_FINGERPRINT;import java.io.File;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.List;import java.util.NoSuchElementException;/** * A service to manage multiple clients that want to access the fingerprint HAL API. * The service is responsible for maintaining a list of clients and dispatching all * fingerprint -related events. * * @hide */public class FingerprintService extends SystemService implements IBinder.DeathRecipient { private static final String TAG = "FingerprintService"; private static final boolean DEBUG = true; private static final String FP_DATA_DIR = "fpdata"; private static final String FINGERPRINTD = "android.hardware.fingerprint.IFingerprintDaemon"; private static final int MSG_USER_SWITCHING = 10; private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute private ClientMonitor mAuthClient = null; private ClientMonitor mEnrollClient = null; private ClientMonitor mRemoveClient = null; private final AppOpsManager mAppOps; private static final long MS_PER_SEC = 1000; private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000; private static final int MAX_FAILED_ATTEMPTS = 5; private static final int FINGERPRINT_ACQUIRED_GOOD = 0; Handler mHandler = new Handler() { @Override public void handleMessage(android.os.Message msg) { switch (msg.what) { case MSG_USER_SWITCHING: handleUserSwitching(msg.arg1); break; default: Slog.w(TAG, "Unknown message:" + msg.what); } } }; private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance(); private Context mContext; private long mHalDeviceId; private int mFailedAttempts; private IFingerprintDaemon mDaemon; private PowerManager mPowerManager; private final Runnable mLockoutReset = new Runnable() { @Override public void run() { resetFailedAttempts(); } }; public FingerprintService(Context context) { super(context); mContext = context; mAppOps = context.getSystemService(AppOpsManager.class); mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); } @Override public void binderDied() { Slog.v(TAG, "fingerprintd died"); mDaemon = null; dispatchError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE); } public IFingerprintDaemon getFingerprintDaemon() { if (mDaemon == null) { mDaemon = IFingerprintDaemon.Stub.asInterface(ServiceManager.getService(FINGERPRINTD)); if (mDaemon != null) { try { mDaemon.asBinder().linkToDeath(this, 0); mDaemon.init(mDaemonCallback); mHalDeviceId = mDaemon.openHal(); if (mHalDeviceId != 0) { updateActiveGroup(ActivityManager.getCurrentUser()); } else { Slog.w(TAG, "Failed to open Fingerprint HAL!"); mDaemon = null; } } catch (RemoteException e) { Slog.e(TAG, "Failed to open fingeprintd HAL", e); mDaemon = null; // try again later! } } else { Slog.w(TAG, "fingerprint service not available"); } } return mDaemon; } protected void dispatchEnumerate(long deviceId, int[] fingerIds, int[] groupIds) { if (fingerIds.length != groupIds.length) { Slog.w(TAG, "fingerIds and groupIds differ in length: f[]=" + fingerIds + ", g[]=" + groupIds); return; } if (DEBUG) Slog.w(TAG, "Enumerate: f[]=" + fingerIds + ", g[]=" + groupIds); // TODO: update fingerprint/name pairs } protected void dispatchRemoved(long deviceId, int fingerId, int groupId) { final ClientMonitor client = mRemoveClient; if (fingerId != 0) { removeTemplateForUser(mRemoveClient, fingerId); } if (client != null && client.sendRemoved(fingerId, groupId)) { removeClient(mRemoveClient); } } protected void dispatchError(long deviceId, int error) { if (mEnrollClient != null) { final IBinder token = mEnrollClient.token; if (mEnrollClient.sendError(error)) { stopEnrollment(token, false); } } else if (mAuthClient != null) { final IBinder token = mAuthClient.token; if (mAuthClient.sendError(error)) { stopAuthentication(token, false); } } else if (mRemoveClient != null) { if (mRemoveClient.sendError(error)) removeClient(mRemoveClient); } } protected void dispatchAuthenticated(long deviceId, int fingerId, int groupId) { if (mAuthClient != null) { final IBinder token = mAuthClient.token; if (mAuthClient.sendAuthenticated(fingerId, groupId)) { stopAuthentication(token, false); removeClient(mAuthClient); } } } protected void dispatchAcquired(long deviceId, int acquiredInfo) { if (mEnrollClient != null) { if (mEnrollClient.sendAcquired(acquiredInfo)) { removeClient(mEnrollClient); } } else if (mAuthClient != null) { if (mAuthClient.sendAcquired(acquiredInfo)) { removeClient(mAuthClient); } } } private void userActivity() { long now = SystemClock.uptimeMillis(); mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0); } void handleUserSwitching(int userId) { updateActiveGroup(userId); } protected void dispatchEnrollResult(long deviceId, int fingerId, int groupId, int remaining) { if (mEnrollClient != null) { if (mEnrollClient.sendEnrollResult(fingerId, groupId, remaining)) { if (remaining == 0) { addTemplateForUser(mEnrollClient, fingerId); removeClient(mEnrollClient); } } } } private void removeClient(ClientMonitor client) { if (client == null) return; client.destroy(); if (client == mAuthClient) { mAuthClient = null; } else if (client == mEnrollClient) { mEnrollClient = null; } else if (client == mRemoveClient) { mRemoveClient = null; } } private boolean inLockoutMode() { return mFailedAttempts > MAX_FAILED_ATTEMPTS; } private void resetFailedAttempts() { if (DEBUG && inLockoutMode()) { Slog.v(TAG, "Reset fingerprint lockout"); } mFailedAttempts = 0; } private boolean handleFailedAttempt(ClientMonitor clientMonitor) { mFailedAttempts++; if (mFailedAttempts > MAX_FAILED_ATTEMPTS) { // Failing multiple times will continue to push out the lockout time. mHandler.removeCallbacks(mLockoutReset); mHandler.postDelayed(mLockoutReset, FAIL_LOCKOUT_TIMEOUT_MS); if (clientMonitor != null && !clientMonitor.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) { Slog.w(TAG, "Cannot send lockout message to client"); } return true; } return false; } private void removeTemplateForUser(ClientMonitor clientMonitor, int fingerId) { mFingerprintUtils.removeFingerprintIdForUser(mContext, fingerId, clientMonitor.userId); } private void addTemplateForUser(ClientMonitor clientMonitor, int fingerId) { mFingerprintUtils.addFingerprintForUser(mContext, fingerId, clientMonitor.userId); } void startEnrollment(IBinder token, byte[] cryptoToken, int groupId, IFingerprintServiceReceiver receiver, int flags, boolean restricted) { IFingerprintDaemon daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "enroll: no fingeprintd!"); return; } stopPendingOperations(true); mEnrollClient = new ClientMonitor(token, receiver, groupId, restricted); final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC); try { final int result = daemon.enroll(cryptoToken, groupId, timeout); if (result != 0) { Slog.w(TAG, "startEnroll failed, result=" + result); } } catch (RemoteException e) { Slog.e(TAG, "startEnroll failed", e); } } public long startPreEnroll(IBinder token) { IFingerprintDaemon daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "startPreEnroll: no fingeprintd!"); return 0; } try { return daemon.preEnroll(); } catch (RemoteException e) { Slog.e(TAG, "startPreEnroll failed", e); } return 0; } public int startPostEnroll(IBinder token) { IFingerprintDaemon daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "startPostEnroll: no fingeprintd!"); return 0; } try { return daemon.postEnroll(); } catch (RemoteException e) { Slog.e(TAG, "startPostEnroll failed", e); } return 0; } private void stopPendingOperations(boolean initiatedByClient) { if (mEnrollClient != null) { stopEnrollment(mEnrollClient.token, initiatedByClient); } if (mAuthClient != null) { stopAuthentication(mAuthClient.token, initiatedByClient); } // mRemoveClient is allowed to continue } /** * Stop enrollment in progress and inform client if they initiated it. * * @param token token for client * @param initiatedByClient if this call is the result of client action (e.g. calling cancel) */ void stopEnrollment(IBinder token, boolean initiatedByClient) { IFingerprintDaemon daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "stopEnrollment: no fingeprintd!"); return; } final ClientMonitor client = mEnrollClient; if (client == null || client.token != token) return; if (initiatedByClient) { try { int result = daemon.cancelEnrollment(); if (result != 0) { Slog.w(TAG, "startEnrollCancel failed, result = " + result); } } catch (RemoteException e) { Slog.e(TAG, "stopEnrollment failed", e); } client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED); } removeClient(mEnrollClient); } void startAuthentication(IBinder token, long opId, int groupId, IFingerprintServiceReceiver receiver, int flags, boolean restricted) { IFingerprintDaemon daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "startAuthentication: no fingeprintd!"); return; } stopPendingOperations(true); mAuthClient = new ClientMonitor(token, receiver, groupId, restricted); if (inLockoutMode()) { Slog.v(TAG, "In lockout mode; disallowing authentication"); if (!mAuthClient.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) { Slog.w(TAG, "Cannot send timeout message to client"); } mAuthClient = null; return; } try { final int result = daemon.authenticate(opId, groupId); if (result != 0) { Slog.w(TAG, "startAuthentication failed, result=" + result); } } catch (RemoteException e) { Slog.e(TAG, "startAuthentication failed", e); } } /** * Stop authentication in progress and inform client if they initiated it. * * @param token token for client * @param initiatedByClient if this call is the result of client action (e.g. calling cancel) */ void stopAuthentication(IBinder token, boolean initiatedByClient) { IFingerprintDaemon daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "stopAuthentication: no fingeprintd!"); return; } final ClientMonitor client = mAuthClient; if (client == null || client.token != token) return; if (initiatedByClient) { try { int result = daemon.cancelAuthentication(); if (result != 0) { Slog.w(TAG, "stopAuthentication failed, result=" + result); } } catch (RemoteException e) { Slog.e(TAG, "stopAuthentication failed", e); } client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED); } removeClient(mAuthClient); } void startRemove(IBinder token, int fingerId, int userId, IFingerprintServiceReceiver receiver, boolean restricted) { IFingerprintDaemon daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "startRemove: no fingeprintd!"); return; } mRemoveClient = new ClientMonitor(token, receiver, userId, restricted); // The fingerprint template ids will be removed when we get confirmation from the HAL try { final int result = daemon.remove(fingerId, userId); if (result != 0) { Slog.w(TAG, "startRemove with id = " + fingerId + " failed, result=" + result); } } catch (RemoteException e) { Slog.e(TAG, "startRemove failed", e); } } public List getEnrolledFingerprints(int userId) { return mFingerprintUtils.getFingerprintsForUser(mContext, userId); } public boolean hasEnrolledFingerprints(int userId) { return mFingerprintUtils.getFingerprintsForUser(mContext, userId).size() > 0; } boolean hasPermission(String permission) { return getContext().checkCallingOrSelfPermission(permission) == PackageManager.PERMISSION_GRANTED; } void checkPermission(String permission) { getContext().enforceCallingOrSelfPermission(permission, "Must have " + permission + " permission."); } int getEffectiveUserId(int userId) { UserManager um = UserManager.get(mContext); if (um != null) { final long callingIdentity = Binder.clearCallingIdentity(); userId = um.getCredentialOwnerProfile(userId); Binder.restoreCallingIdentity(callingIdentity); } else { Slog.e(TAG, "Unable to acquire UserManager"); } return userId; } boolean isCurrentUserOrProfile(int userId) { UserManager um = UserManager.get(mContext); // Allow current user or profiles of the current user... List profiles = um.getEnabledProfiles(userId); final int n = profiles.size(); for (int i = 0; i < n; i++) { if (profiles.get(i).id == userId) { return true; } } return false; } private boolean canUseFingerprint(String opPackageName) { checkPermission(USE_FINGERPRINT); return mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, Binder.getCallingUid(), opPackageName) == AppOpsManager.MODE_ALLOWED; } private class ClientMonitor implements IBinder.DeathRecipient { IBinder token; IFingerprintServiceReceiver receiver; int userId; boolean restricted; // True if client does not have MANAGE_FINGERPRINT permission public ClientMonitor(IBinder token, IFingerprintServiceReceiver receiver, int userId, boolean restricted) { this.token = token; this.receiver = receiver; this.userId = userId; this.restricted = restricted; try { token.linkToDeath(this, 0); } catch (RemoteException e) { Slog.w(TAG, "caught remote exception in linkToDeath: ", e); } } public void destroy() { if (token != null) { try { token.unlinkToDeath(this, 0); } catch (NoSuchElementException e) { // TODO: remove when duplicate call bug is found Slog.e(TAG, "destroy(): " + this + ":", new Exception("here")); } token = null; } receiver = null; } @Override public void binderDied() { token = null; removeClient(this); receiver = null; } @Override protected void finalize() throws Throwable { try { if (token != null) { if (DEBUG) Slog.w(TAG, "removing leaked reference: " + token); removeClient(this); } } finally { super.finalize(); } } /* * @return true if we're done. */ private boolean sendRemoved(int fingerId, int groupId) { if (receiver == null) return true; // client not listening try { receiver.onRemoved(mHalDeviceId, fingerId, groupId); return fingerId == 0; } catch (RemoteException e) { Slog.w(TAG, "Failed to notify Removed:", e); } return false; } /* * @return true if we're done. */ private boolean sendEnrollResult(int fpId, int groupId, int remaining) { if (receiver == null) return true; // client not listening FingerprintUtils.vibrateFingerprintSuccess(getContext()); try { receiver.onEnrollResult(mHalDeviceId, fpId, groupId, remaining); return remaining == 0; } catch (RemoteException e) { Slog.w(TAG, "Failed to notify EnrollResult:", e); return true; } } /* * @return true if we're done. */ private boolean sendAuthenticated(int fpId, int groupId) { boolean result = false; boolean authenticated = fpId != 0; if (receiver != null) { try { if (!authenticated) { receiver.onAuthenticationFailed(mHalDeviceId); } else { Fingerprint fp = !restricted ? new Fingerprint("" /* TODO */, groupId, fpId, mHalDeviceId) : null; receiver.onAuthenticationSucceeded(mHalDeviceId, fp); } } catch (RemoteException e) { Slog.w(TAG, "Failed to notify Authenticated:", e); result = true; // client failed } } else { result = true; // client not listening } if (fpId == 0) { FingerprintUtils.vibrateFingerprintError(getContext()); result |= handleFailedAttempt(this); } else { FingerprintUtils.vibrateFingerprintSuccess(getContext()); result |= true; // we have a valid fingerprint mLockoutReset.run(); } return result; } /* * @return true if we're done. */ private boolean sendAcquired(int acquiredInfo) { if (receiver == null) return true; // client not listening try { receiver.onAcquired(mHalDeviceId, acquiredInfo); return false; // acquisition continues... } catch (RemoteException e) { Slog.w(TAG, "Failed to invoke sendAcquired:", e); return true; // client failed } finally { // Good scans will keep the device awake if (acquiredInfo == FINGERPRINT_ACQUIRED_GOOD) { userActivity(); } } } /* * @return true if we're done. */ private boolean sendError(int error) { if (receiver != null) { try { receiver.onError(mHalDeviceId, error); } catch (RemoteException e) { Slog.w(TAG, "Failed to invoke sendError:", e); } } return true; // errors always terminate progress } } private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() { @Override public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) { dispatchEnrollResult(deviceId, fingerId, groupId, remaining); } @Override public void onAcquired(long deviceId, int acquiredInfo) { dispatchAcquired(deviceId, acquiredInfo); } @Override public void onAuthenticated(long deviceId, int fingerId, int groupId) { dispatchAuthenticated(deviceId, fingerId, groupId); } @Override public void onError(long deviceId, int error) { dispatchError(deviceId, error); } @Override public void onRemoved(long deviceId, int fingerId, int groupId) { dispatchRemoved(deviceId, fingerId, groupId); } @Override public void onEnumerate(long deviceId, int[] fingerIds, int[] groupIds) { dispatchEnumerate(deviceId, fingerIds, groupIds); } }; private final class FingerprintServiceWrapper extends IFingerprintService.Stub { private static final String KEYGUARD_PACKAGE = "com.android.systemui"; @Override // Binder call public long preEnroll(IBinder token) { checkPermission(MANAGE_FINGERPRINT); return startPreEnroll(token); } @Override // Binder call public int postEnroll(IBinder token) { checkPermission(MANAGE_FINGERPRINT); return startPostEnroll(token); } @Override // Binder call public void enroll(final IBinder token, final byte[] cryptoToken, final int groupId, final IFingerprintServiceReceiver receiver, final int flags) { checkPermission(MANAGE_FINGERPRINT); final int limit = mContext.getResources().getInteger( com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser); final int callingUid = Binder.getCallingUid(); final int userId = UserHandle.getUserId(callingUid); final int enrolled = FingerprintService.this.getEnrolledFingerprints(userId).size(); if (enrolled >= limit) { Slog.w(TAG, "Too many fingerprints registered"); return; } final byte [] cryptoClone = Arrays.copyOf(cryptoToken, cryptoToken.length); // Group ID is arbitrarily set to parent profile user ID. It just represents // the default fingerprints for the user. final int effectiveGroupId = getEffectiveUserId(groupId); final boolean restricted = isRestricted(); mHandler.post(new Runnable() { @Override public void run() { startEnrollment(token, cryptoClone, effectiveGroupId, receiver, flags, restricted); } }); } private boolean isRestricted() { // Only give privileged apps (like Settings) access to fingerprint info final boolean restricted = !hasPermission(MANAGE_FINGERPRINT); return restricted; } @Override // Binder call public void cancelEnrollment(final IBinder token) { checkPermission(MANAGE_FINGERPRINT); mHandler.post(new Runnable() { @Override public void run() { stopEnrollment(token, true); } }); } @Override // Binder call public void authenticate(final IBinder token, final long opId, final int groupId, final IFingerprintServiceReceiver receiver, final int flags, final String opPackageName) { if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) { Slog.w(TAG, "Can't authenticate non-current user"); return; } if (!canUseFingerprint(opPackageName)) { Slog.w(TAG, "Calling not granted permission to use fingerprint"); return; } // Group ID is arbitrarily set to parent profile user ID. It just represents // the default fingerprints for the user. final int effectiveGroupId = getEffectiveUserId(groupId); final boolean restricted = isRestricted(); mHandler.post(new Runnable() { @Override public void run() { startAuthentication(token, opId, effectiveGroupId, receiver, flags, restricted); } }); } @Override // Binder call public void cancelAuthentication(final IBinder token, String opPackageName) { if (!canUseFingerprint(opPackageName)) { return; } mHandler.post(new Runnable() { @Override public void run() { stopAuthentication(token, true); } }); } @Override // Binder call public void remove(final IBinder token, final int fingerId, final int groupId, final IFingerprintServiceReceiver receiver) { checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission final boolean restricted = isRestricted(); // Group ID is arbitrarily set to parent profile user ID. It just represents // the default fingerprints for the user. final int effectiveGroupId = getEffectiveUserId(groupId); mHandler.post(new Runnable() { @Override public void run() { startRemove(token, fingerId, effectiveGroupId, receiver, restricted); } }); } @Override // Binder call public boolean isHardwareDetected(long deviceId, String opPackageName) { if (!canUseFingerprint(opPackageName)) { return false; } return mHalDeviceId != 0; } @Override // Binder call public void rename(final int fingerId, final int groupId, final String name) { checkPermission(MANAGE_FINGERPRINT); // Group ID is arbitrarily set to parent profile user ID. It just represents // the default fingerprints for the user. final int effectiveGroupId = getEffectiveUserId(groupId); mHandler.post(new Runnable() { @Override public void run() { mFingerprintUtils.renameFingerprintForUser(mContext, fingerId, effectiveGroupId, name); } }); } @Override // Binder call public List getEnrolledFingerprints(int userId, String opPackageName) { if (!canUseFingerprint(opPackageName)) { return Collections.emptyList(); } int effectiveUserId = getEffectiveUserId(userId); return FingerprintService.this.getEnrolledFingerprints(effectiveUserId); } @Override // Binder call public boolean hasEnrolledFingerprints(int userId, String opPackageName) { if (!canUseFingerprint(opPackageName)) { return false; } int effectiveUserId = getEffectiveUserId(userId); return FingerprintService.this.hasEnrolledFingerprints(effectiveUserId); } @Override // Binder call public long getAuthenticatorId(String opPackageName) { // In this method, we're not checking whether the caller is permitted to use fingerprint // API because current authenticator ID is leaked (in a more contrived way) via Android // Keystore (android.security.keystore package): the user of that API can create a key // which requires fingerprint authentication for its use, and then query the key's // characteristics (hidden API) which returns, among other things, fingerprint // authenticator ID which was active at key creation time. // // Reason: The part of Android Keystore which runs inside an app's process invokes this // method in certain cases. Those cases are not always where the developer demonstrates // explicit intent to use fingerprint functionality. Thus, to avoiding throwing an // unexpected SecurityException this method does not check whether its caller is // permitted to use fingerprint API. // // The permission check should be restored once Android Keystore no longer invokes this // method from inside app processes. return FingerprintService.this.getAuthenticatorId(); } } @Override public void onStart() { publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper()); IFingerprintDaemon daemon = getFingerprintDaemon(); if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId); listenForUserSwitches(); } private void updateActiveGroup(int userId) { IFingerprintDaemon daemon = getFingerprintDaemon(); if (daemon != null) { try { userId = getEffectiveUserId(userId); final File systemDir = Environment.getUserSystemDirectory(userId); final File fpDir = new File(systemDir, FP_DATA_DIR); if (!fpDir.exists()) { if (!fpDir.mkdir()) { Slog.v(TAG, "Cannot make directory: " + fpDir.getAbsolutePath()); return; } // Calling mkdir() from this process will create a directory with our // permissions (inherited from the containing dir). This command fixes // the label. if (!SELinux.restorecon(fpDir)) { Slog.w(TAG, "Restorecons failed. Directory will have wrong label."); return; } } daemon.setActiveGroup(userId, fpDir.getAbsolutePath().getBytes()); } catch (RemoteException e) { Slog.e(TAG, "Failed to setActiveGroup():", e); } } } private void listenForUserSwitches() { try { ActivityManagerNative.getDefault().registerUserSwitchObserver( new IUserSwitchObserver.Stub() { @Override public void onUserSwitching(int newUserId, IRemoteCallback reply) { mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */) .sendToTarget(); } @Override public void onUserSwitchComplete(int newUserId) throws RemoteException { // Ignore. } @Override public void onForegroundProfileSwitch(int newProfileId) { // Ignore. } }); } catch (RemoteException e) { Slog.w(TAG, "Failed to listen for user switching event" ,e); } } public long getAuthenticatorId() { IFingerprintDaemon daemon = getFingerprintDaemon(); if (daemon != null) { try { return daemon.getAuthenticatorId(); } catch (RemoteException e) { Slog.e(TAG, "getAuthenticatorId failed", e); } } return 0; }}
FingerprintsUserState.java
/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */package com.android.server.fingerprint;import android.content.Context;import android.hardware.fingerprint.Fingerprint;import android.os.AsyncTask;import android.os.Environment;import android.util.AtomicFile;import android.util.Slog;import android.util.Xml;import com.android.internal.annotations.GuardedBy;import libcore.io.IoUtils;import org.xmlpull.v1.XmlPullParser;import org.xmlpull.v1.XmlPullParserException;import org.xmlpull.v1.XmlSerializer;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.util.ArrayList;import java.util.List;/** * Class managing the set of fingerprint per user across device reboots. */class FingerprintsUserState { private static final String TAG = "FingerprintState"; private static final String FINGERPRINT_FILE = "settings_fingerprint.xml"; private static final String TAG_FINGERPRINTS = "fingerprints"; private static final String TAG_FINGERPRINT = "fingerprint"; private static final String ATTR_NAME = "name"; private static final String ATTR_GROUP_ID = "groupId"; private static final String ATTR_FINGER_ID = "fingerId"; private static final String ATTR_DEVICE_ID = "deviceId"; private final File mFile; @GuardedBy("this") private final ArrayList mFingerprints = new ArrayList(); private final Context mCtx; public FingerprintsUserState(Context ctx, int userId) { mFile = getFileForUser(userId); mCtx = ctx; synchronized (this) { readStateSyncLocked(); } } public void addFingerprint(int fingerId, int groupId) { synchronized (this) { mFingerprints.add(new Fingerprint(getUniqueName(), groupId, fingerId, 0)); scheduleWriteStateLocked(); } } public void removeFingerprint(int fingerId) { synchronized (this) { for (int i = 0; i < mFingerprints.size(); i++) { if (mFingerprints.get(i).getFingerId() == fingerId) { mFingerprints.remove(i); scheduleWriteStateLocked(); break; } } } } public void renameFingerprint(int fingerId, CharSequence name) { synchronized (this) { for (int i = 0; i < mFingerprints.size(); i++) { if (mFingerprints.get(i).getFingerId() == fingerId) { Fingerprint old = mFingerprints.get(i); mFingerprints.set(i, new Fingerprint(name, old.getGroupId(), old.getFingerId(), old.getDeviceId())); scheduleWriteStateLocked(); break; } } } } public List getFingerprints() { synchronized (this) { return getCopy(mFingerprints); } } /** * Finds a unique name for the given fingerprint * @return unique name */ private String getUniqueName() { int guess = 1; while (true) { // Not the most efficient algorithm in the world, but there shouldn't be more than 10 String name = mCtx.getString(com.android.internal.R.string.fingerprint_name_template, guess); if (isUnique(name)) { return name; } guess++; } } private boolean isUnique(String name) { for (Fingerprint fp : mFingerprints) { if (fp.getName().equals(name)) { return false; } } return true; } private static File getFileForUser(int userId) { return new File(Environment.getUserSystemDirectory(userId), FINGERPRINT_FILE); } private final Runnable mWriteStateRunnable = new Runnable() { @Override public void run() { doWriteState(); } }; private void scheduleWriteStateLocked() { AsyncTask.execute(mWriteStateRunnable); } private ArrayList getCopy(ArrayList array) { ArrayList result = new ArrayList(array.size()); for (int i = 0; i < array.size(); i++) { Fingerprint fp = array.get(i); result.add(new Fingerprint(fp.getName(), fp.getGroupId(), fp.getFingerId(), fp.getDeviceId())); } return result; } private void doWriteState() { AtomicFile destination = new AtomicFile(mFile); ArrayList fingerprints; synchronized (this) { fingerprints = getCopy(mFingerprints); } FileOutputStream out = null; try { out = destination.startWrite(); XmlSerializer serializer = Xml.newSerializer(); serializer.setOutput(out, "utf-8"); serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); serializer.startDocument(null, true); serializer.startTag(null, TAG_FINGERPRINTS); final int count = fingerprints.size(); for (int i = 0; i < count; i++) { Fingerprint fp = fingerprints.get(i); serializer.startTag(null, TAG_FINGERPRINT); serializer.attribute(null, ATTR_FINGER_ID, Integer.toString(fp.getFingerId())); serializer.attribute(null, ATTR_NAME, fp.getName().toString()); serializer.attribute(null, ATTR_GROUP_ID, Integer.toString(fp.getGroupId())); serializer.attribute(null, ATTR_DEVICE_ID, Long.toString(fp.getDeviceId())); serializer.endTag(null, TAG_FINGERPRINT); } serializer.endTag(null, TAG_FINGERPRINTS); serializer.endDocument(); destination.finishWrite(out); // Any error while writing is fatal. } catch (Throwable t) { Slog.wtf(TAG, "Failed to write settings, restoring backup", t); destination.failWrite(out); throw new IllegalStateException("Failed to write fingerprints", t); } finally { IoUtils.closeQuietly(out); } } private void readStateSyncLocked() { FileInputStream in; if (!mFile.exists()) { return; } try { in = new FileInputStream(mFile); } catch (FileNotFoundException fnfe) { Slog.i(TAG, "No fingerprint state"); return; } try { XmlPullParser parser = Xml.newPullParser(); parser.setInput(in, null); parseStateLocked(parser); } catch (XmlPullParserException | IOException e) { throw new IllegalStateException("Failed parsing settings file: " + mFile , e); } finally { IoUtils.closeQuietly(in); } } private void parseStateLocked(XmlPullParser parser) throws IOException, XmlPullParserException { final int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } String tagName = parser.getName(); if (tagName.equals(TAG_FINGERPRINTS)) { parseFingerprintsLocked(parser); } } } private void parseFingerprintsLocked(XmlPullParser parser) throws IOException, XmlPullParserException { final int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } String tagName = parser.getName(); if (tagName.equals(TAG_FINGERPRINT)) { String name = parser.getAttributeValue(null, ATTR_NAME); String groupId = parser.getAttributeValue(null, ATTR_GROUP_ID); String fingerId = parser.getAttributeValue(null, ATTR_FINGER_ID); String deviceId = parser.getAttributeValue(null, ATTR_DEVICE_ID); mFingerprints.add(new Fingerprint(name, Integer.parseInt(groupId), Integer.parseInt(fingerId), Integer.parseInt(deviceId))); } } }}
FingerprintUtils.java
/** * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.android.server.fingerprint;import android.content.Context;import android.hardware.fingerprint.Fingerprint;import android.os.Vibrator;import android.util.SparseArray;import com.android.internal.annotations.GuardedBy;import java.util.List;/** * Utility class for dealing with fingerprints and fingerprint settings. */public class FingerprintUtils { private static final long[] FP_ERROR_VIBRATE_PATTERN = new long[] {0, 30, 100, 30}; private static final long[] FP_SUCCESS_VIBRATE_PATTERN = new long[] {0, 30}; private static final Object sInstanceLock = new Object(); private static FingerprintUtils sInstance; @GuardedBy("this") private final SparseArray mUsers = new SparseArray<>(); public static FingerprintUtils getInstance() { synchronized (sInstanceLock) { if (sInstance == null) { sInstance = new FingerprintUtils(); } } return sInstance; } private FingerprintUtils() { } public List getFingerprintsForUser(Context ctx, int userId) { return getStateForUser(ctx, userId).getFingerprints(); } public void addFingerprintForUser(Context ctx, int fingerId, int userId) { getStateForUser(ctx, userId).addFingerprint(fingerId, userId); } public void removeFingerprintIdForUser(Context ctx, int fingerId, int userId) { getStateForUser(ctx, userId).removeFingerprint(fingerId); } public void renameFingerprintForUser(Context ctx, int fingerId, int userId, CharSequence name) { getStateForUser(ctx, userId).renameFingerprint(fingerId, name); } public static void vibrateFingerprintError(Context context) { Vibrator vibrator = context.getSystemService(Vibrator.class); if (vibrator != null) { vibrator.vibrate(FP_ERROR_VIBRATE_PATTERN, -1); } } public static void vibrateFingerprintSuccess(Context context) { Vibrator vibrator = context.getSystemService(Vibrator.class); if (vibrator != null) { vibrator.vibrate(FP_SUCCESS_VIBRATE_PATTERN, -1); } } private FingerprintsUserState getStateForUser(Context ctx, int userId) { synchronized (this) { FingerprintsUserState state = mUsers.get(userId); if (state == null) { state = new FingerprintsUserState(ctx, userId); mUsers.put(userId, state); } return state; } }}
/frameworks/base/core/java/android/hardware/fingerprint/
-------------------------------------------------------------------------------------------
Fingerprint.aidl
/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package android.hardware.fingerprint;// @hideparcelable Fingerprint;
Fingerprint.java
/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package android.hardware.fingerprint;import android.os.Parcel;import android.os.Parcelable;/** * Container for fingerprint metadata. * @hide */public final class Fingerprint implements Parcelable { private CharSequence mName; private int mGroupId; private int mFingerId; private long mDeviceId; // physical device this is associated with public Fingerprint(CharSequence name, int groupId, int fingerId, long deviceId) { mName = name; mGroupId = groupId; mFingerId = fingerId; mDeviceId = deviceId; } private Fingerprint(Parcel in) { mName = in.readString(); mGroupId = in.readInt(); mFingerId = in.readInt(); mDeviceId = in.readLong(); } /** * Gets the human-readable name for the given fingerprint. * @return name given to finger */ public CharSequence getName() { return mName; } /** * Gets the device-specific finger id. Used by Settings to map a name to a specific * fingerprint template. * @return device-specific id for this finger * @hide */ public int getFingerId() { return mFingerId; } /** * Gets the group id specified when the fingerprint was enrolled. * @return group id for the set of fingerprints this one belongs to. * @hide */ public int getGroupId() { return mGroupId; } /** * Device this fingerprint belongs to. * @hide */ public long getDeviceId() { return mDeviceId; } public int describeContents() { return 0; } public void writeToParcel(Parcel out, int flags) { out.writeString(mName.toString()); out.writeInt(mGroupId); out.writeInt(mFingerId); out.writeLong(mDeviceId); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public Fingerprint createFromParcel(Parcel in) { return new Fingerprint(in); } public Fingerprint[] newArray(int size) { return new Fingerprint[size]; } };};
FingerprintManager.java
/** * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package android.hardware.fingerprint;import android.annotation.NonNull;import android.annotation.Nullable;import android.annotation.RequiresPermission;import android.app.ActivityManagerNative;import android.content.Context;import android.os.Binder;import android.os.CancellationSignal;import android.os.CancellationSignal.OnCancelListener;import android.os.Handler;import android.os.IBinder;import android.os.Looper;import android.os.RemoteException;import android.os.UserHandle;import android.security.keystore.AndroidKeyStoreProvider;import android.util.Log;import android.util.Slog;import java.security.Signature;import java.util.List;import javax.crypto.Cipher;import javax.crypto.Mac;import static android.Manifest.permission.USE_FINGERPRINT;import static android.Manifest.permission.MANAGE_FINGERPRINT;/** * A class that coordinates access to the fingerprint hardware. * * Use {@link android.content.Context#getSystemService(java.lang.String)} * with argument {@link android.content.Context#FINGERPRINT_SERVICE} to get * an instance of this class. */public class FingerprintManager { private static final String TAG = "FingerprintManager"; private static final boolean DEBUG = true; private static final int MSG_ENROLL_RESULT = 100; private static final int MSG_ACQUIRED = 101; private static final int MSG_AUTHENTICATION_SUCCEEDED = 102; private static final int MSG_AUTHENTICATION_FAILED = 103; private static final int MSG_ERROR = 104; private static final int MSG_REMOVED = 105; // // Error messages from fingerprint hardware during initilization, enrollment, authentication or // removal. Must agree with the list in fingerprint.h // /** * The hardware is unavailable. Try again later. */ public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; /** * Error state returned when the sensor was unable to process the current image. */ public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; /** * Error state returned when the current request has been running too long. This is intended to * prevent programs from waiting for the fingerprint sensor indefinitely. The timeout is * platform and sensor-specific, but is generally on the order of 30 seconds. */ public static final int FINGERPRINT_ERROR_TIMEOUT = 3; /** * Error state returned for operations like enrollment; the operation cannot be completed * because there's not enough storage remaining to complete the operation. */ public static final int FINGERPRINT_ERROR_NO_SPACE = 4; /** * The operation was canceled because the fingerprint sensor is unavailable. For example, * this may happen when the user is switched, the device is locked or another pending operation * prevents or disables it. */ public static final int FINGERPRINT_ERROR_CANCELED = 5; /** * The {@link FingerprintManager#remove(Fingerprint, RemovalCallback)} call failed. Typically * this will happen when the provided fingerprint id was incorrect. * * @hide */ public static final int FINGERPRINT_ERROR_UNABLE_TO_REMOVE = 6; /** * The operation was canceled because the API is locked out due to too many attempts. */ public static final int FINGERPRINT_ERROR_LOCKOUT = 7; /** * Hardware vendors may extend this list if there are conditions that do not fall under one of * the above categories. Vendors are responsible for providing error strings for these errors. * @hide */ public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000; // // Image acquisition messages. Must agree with those in fingerprint.h // /** * The image acquired was good. */ public static final int FINGERPRINT_ACQUIRED_GOOD = 0; /** * Only a partial fingerprint image was detected. During enrollment, the user should be * informed on what needs to happen to resolve this problem, e.g. "press firmly on sensor." */ public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; /** * The fingerprint image was too noisy to process due to a detected condition (i.e. dry skin) or * a possibly dirty sensor (See {@link #FINGERPRINT_ACQUIRED_IMAGER_DIRTY}). */ public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; /** * The fingerprint image was too noisy due to suspected or detected dirt on the sensor. * For example, it's reasonable return this after multiple * {@link #FINGERPRINT_ACQUIRED_INSUFFICIENT} or actual detection of dirt on the sensor * (stuck pixels, swaths, etc.). The user is expected to take action to clean the sensor * when this is returned. */ public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; /** * The fingerprint image was unreadable due to lack of motion. This is most appropriate for * linear array sensors that require a swipe motion. */ public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; /** * The fingerprint image was incomplete due to quick motion. While mostly appropriate for * linear array sensors, this could also happen if the finger was moved during acquisition. * The user should be asked to move the finger slower (linear) or leave the finger on the sensor * longer. */ public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; /** * Hardware vendors may extend this list if there are conditions that do not fall under one of * the above categories. Vendors are responsible for providing error strings for these errors. * @hide */ public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000; private IFingerprintService mService; private Context mContext; private IBinder mToken = new Binder(); private AuthenticationCallback mAuthenticationCallback; private EnrollmentCallback mEnrollmentCallback; private RemovalCallback mRemovalCallback; private CryptoObject mCryptoObject; private Fingerprint mRemovalFingerprint; private Handler mHandler; private class OnEnrollCancelListener implements OnCancelListener { @Override public void onCancel() { cancelEnrollment(); } } private class OnAuthenticationCancelListener implements OnCancelListener { private CryptoObject mCrypto; public OnAuthenticationCancelListener(CryptoObject crypto) { mCrypto = crypto; } @Override public void onCancel() { cancelAuthentication(mCrypto); } } /** * A wrapper class for the crypto objects supported by FingerprintManager. Currently the * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects. */ public static final class CryptoObject { public CryptoObject(@NonNull Signature signature) { mCrypto = signature; } public CryptoObject(@NonNull Cipher cipher) { mCrypto = cipher; } public CryptoObject(@NonNull Mac mac) { mCrypto = mac; } /** * Get {@link Signature} object. * @return {@link Signature} object or null if this doesn't contain one. */ public Signature getSignature() { return mCrypto instanceof Signature ? (Signature) mCrypto : null; } /** * Get {@link Cipher} object. * @return {@link Cipher} object or null if this doesn't contain one. */ public Cipher getCipher() { return mCrypto instanceof Cipher ? (Cipher) mCrypto : null; } /** * Get {@link Mac} object. * @return {@link Mac} object or null if this doesn't contain one. */ public Mac getMac() { return mCrypto instanceof Mac ? (Mac) mCrypto : null; } /** * @hide * @return the opId associated with this object or 0 if none */ public long getOpId() { return mCrypto != null ? AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCrypto) : 0; } private final Object mCrypto; }; /** * Container for callback data from {@link FingerprintManager#authenticate(CryptoObject, * CancellationSignal, int, AuthenticationCallback, Handler)}. */ public static class AuthenticationResult { private Fingerprint mFingerprint; private CryptoObject mCryptoObject; /** * Authentication result * * @param crypto the crypto object * @param fingerprint the recognized fingerprint data, if allowed. * @hide */ public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint) { mCryptoObject = crypto; mFingerprint = fingerprint; } /** * Obtain the crypto object associated with this transaction * @return crypto object provided to {@link FingerprintManager#authenticate(CryptoObject, * CancellationSignal, int, AuthenticationCallback, Handler)}. */ public CryptoObject getCryptoObject() { return mCryptoObject; } /** * Obtain the Fingerprint associated with this operation. Applications are strongly * discouraged from associating specific fingers with specific applications or operations. * * @hide */ public Fingerprint getFingerprint() { return mFingerprint; } }; /** * Callback structure provided to {@link FingerprintManager#authenticate(CryptoObject, * CancellationSignal, int, AuthenticationCallback, Handler)}. Users of {@link * FingerprintManager#authenticate(CryptoObject, CancellationSignal, * int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to * fingerprint events. */ public static abstract class AuthenticationCallback { /** * Called when an unrecoverable error has been encountered and the operation is complete. * No further callbacks will be made on this object. * @param errorCode An integer identifying the error message * @param errString A human-readable error string that can be shown in UI */ public void onAuthenticationError(int errorCode, CharSequence errString) { } /** * Called when a recoverable error has been encountered during authentication. The help * string is provided to give the user guidance for what went wrong, such as * "Sensor dirty, please clean it." * @param helpCode An integer identifying the error message * @param helpString A human-readable string that can be shown in UI */ public void onAuthenticationHelp(int helpCode, CharSequence helpString) { } /** * Called when a fingerprint is recognized. * @param result An object containing authentication-related data */ public void onAuthenticationSucceeded(AuthenticationResult result) { } /** * Called when a fingerprint is valid but not recognized. */ public void onAuthenticationFailed() { } /** * Called when a fingerprint image has been acquired, but wasn't processed yet. * * @param acquireInfo one of FINGERPRINT_ACQUIRED_* constants * @hide */ public void onAuthenticationAcquired(int acquireInfo) {} }; /** * Callback structure provided to {@link FingerprintManager#enroll(long, EnrollmentCallback, * CancellationSignal, int). Users of {@link #FingerprintManager()} * must provide an implementation of this to {@link FingerprintManager#enroll(long, * CancellationSignal, int, EnrollmentCallback) for listening to fingerprint events. * * @hide */ public static abstract class EnrollmentCallback { /** * Called when an unrecoverable error has been encountered and the operation is complete. * No further callbacks will be made on this object. * @param errMsgId An integer identifying the error message * @param errString A human-readable error string that can be shown in UI */ public void onEnrollmentError(int errMsgId, CharSequence errString) { } /** * Called when a recoverable error has been encountered during enrollment. The help * string is provided to give the user guidance for what went wrong, such as * "Sensor dirty, please clean it" or what they need to do next, such as * "Touch sensor again." * @param helpMsgId An integer identifying the error message * @param helpString A human-readable string that can be shown in UI */ public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) { } /** * Called as each enrollment step progresses. Enrollment is considered complete when * remaining reaches 0. This function will not be called if enrollment fails. See * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} * @param remaining The number of remaining steps */ public void onEnrollmentProgress(int remaining) { } }; /** * Callback structure provided to {@link FingerprintManager#remove(int). Users of * {@link #FingerprintManager()} may optionally provide an implementation of this to * {@link FingerprintManager#remove(int, int, RemovalCallback)} for listening to * fingerprint template removal events. * * @hide */ public static abstract class RemovalCallback { /** * Called when the given fingerprint can't be removed. * @param fp The fingerprint that the call attempted to remove * @param errMsgId An associated error message id * @param errString An error message indicating why the fingerprint id can't be removed */ public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) { } /** * Called when a given fingerprint is successfully removed. * @param fingerprint the fingerprint template that was removed. */ public void onRemovalSucceeded(Fingerprint fingerprint) { } }; /** * Request authentication of a crypto object. This call warms up the fingerprint hardware * and starts scanning for a fingerprint. It terminates when * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at * which point the object is no longer valid. The operation can be canceled by using the * provided cancel object. * * @param crypto object associated with the call or null if none required. * @param cancel an object that can be used to cancel authentication * @param flags optional flags; should be 0 * @param callback an object to receive authentication events * @param handler an optional handler to handle callback events * * @throws IllegalArgumentException if the crypto operation is not supported or is not backed * by Android Keystore * facility. * @throws IllegalStateException if the crypto primitive is not initialized. */ @RequiresPermission(USE_FINGERPRINT) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) { authenticate(crypto, cancel, flags, callback, handler, UserHandle.myUserId()); } /** * Use the provided handler thread for events. * @param handler */ private void useHandler(Handler handler) { if (handler != null) { mHandler = new MyHandler(handler.getLooper()); } else if (mHandler.getLooper() != mContext.getMainLooper()){ mHandler = new MyHandler(mContext.getMainLooper()); } } /** * Per-user version * @hide */ @RequiresPermission(USE_FINGERPRINT) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) { if (callback == null) { throw new IllegalArgumentException("Must supply an authentication callback"); } if (cancel != null) { if (cancel.isCanceled()) { Log.w(TAG, "authentication already canceled"); return; } else { cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto)); } } if (mService != null) try { useHandler(handler); mAuthenticationCallback = callback; mCryptoObject = crypto; long sessionId = crypto != null ? crypto.getOpId() : 0; mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags, mContext.getOpPackageName()); } catch (RemoteException e) { Log.w(TAG, "Remote exception while authenticating: ", e); if (callback != null) { // Though this may not be a hardware issue, it will cause apps to give up or try // again later. callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE, getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE)); } } } /** * Request fingerprint enrollment. This call warms up the fingerprint hardware * and starts scanning for fingerprints. Progress will be indicated by callbacks to the * {@link EnrollmentCallback} object. It terminates when * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at * which point the object is no longer valid. The operation can be canceled by using the * provided cancel object. * @param token a unique token provided by a recent creation or verification of device * credentials (e.g. pin, pattern or password). * @param cancel an object that can be used to cancel enrollment * @param flags optional flags * @param callback an object to receive enrollment events * @hide */ @RequiresPermission(MANAGE_FINGERPRINT) public void enroll(byte [] token, CancellationSignal cancel, int flags, EnrollmentCallback callback) { if (callback == null) { throw new IllegalArgumentException("Must supply an enrollment callback"); } if (cancel != null) { if (cancel.isCanceled()) { Log.w(TAG, "enrollment already canceled"); return; } else { cancel.setOnCancelListener(new OnEnrollCancelListener()); } } if (mService != null) try { mEnrollmentCallback = callback; mService.enroll(mToken, token, getCurrentUserId(), mServiceReceiver, flags); } catch (RemoteException e) { Log.w(TAG, "Remote exception in enroll: ", e); if (callback != null) { // Though this may not be a hardware issue, it will cause apps to give up or try // again later. callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE, getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE)); } } } /** * Requests a pre-enrollment auth token to tie enrollment to the confirmation of * existing device credentials (e.g. pin/pattern/password). * @hide */ @RequiresPermission(MANAGE_FINGERPRINT) public long preEnroll() { long result = 0; if (mService != null) try { result = mService.preEnroll(mToken); } catch (RemoteException e) { Log.w(TAG, "Remote exception in enroll: ", e); } return result; } /** * Finishes enrollment and cancels the current auth token. * @hide */ @RequiresPermission(MANAGE_FINGERPRINT) public int postEnroll() { int result = 0; if (mService != null) try { result = mService.postEnroll(mToken); } catch (RemoteException e) { Log.w(TAG, "Remote exception in post enroll: ", e); } return result; } /** * Remove given fingerprint template from fingerprint hardware and/or protected storage. * @param fp the fingerprint item to remove * @param callback an optional callback to verify that fingerprint templates have been * successfully removed. May be null of no callback is required. * * @hide */ @RequiresPermission(MANAGE_FINGERPRINT) public void remove(Fingerprint fp, RemovalCallback callback) { if (mService != null) try { mRemovalCallback = callback; mRemovalFingerprint = fp; mService.remove(mToken, fp.getFingerId(), getCurrentUserId(), mServiceReceiver); } catch (RemoteException e) { Log.w(TAG, "Remote exception in remove: ", e); if (callback != null) { callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE, getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE)); } } } /** * Renames the given fingerprint template * @param fpId the fingerprint id * @param newName the new name * * @hide */ @RequiresPermission(MANAGE_FINGERPRINT) public void rename(int fpId, String newName) { // Renames the given fpId if (mService != null) { try { mService.rename(fpId, getCurrentUserId(), newName); } catch (RemoteException e) { Log.v(TAG, "Remote exception in rename(): ", e); } } else { Log.w(TAG, "rename(): Service not connected!"); } } /** * Obtain the list of enrolled fingerprints templates. * @return list of current fingerprint items * * @hide */ @RequiresPermission(USE_FINGERPRINT) public List getEnrolledFingerprints(int userId) { if (mService != null) try { return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName()); } catch (RemoteException e) { Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e); } return null; } /** * Obtain the list of enrolled fingerprints templates. * @return list of current fingerprint items * * @hide */ @RequiresPermission(USE_FINGERPRINT) public List getEnrolledFingerprints() { return getEnrolledFingerprints(UserHandle.myUserId()); } /** * Determine if there is at least one fingerprint enrolled. * * @return true if at least one fingerprint is enrolled, false otherwise */ @RequiresPermission(USE_FINGERPRINT) public boolean hasEnrolledFingerprints() { if (mService != null) try { return mService.hasEnrolledFingerprints(UserHandle.myUserId(), mContext.getOpPackageName()); } catch (RemoteException e) { Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e); } return false; } /** * Determine if fingerprint hardware is present and functional. * * @return true if hardware is present and functional, false otherwise. */ @RequiresPermission(USE_FINGERPRINT) public boolean isHardwareDetected() { if (mService != null) { try { long deviceId = 0; /* TODO: plumb hardware id to FPMS */ return mService.isHardwareDetected(deviceId, mContext.getOpPackageName()); } catch (RemoteException e) { Log.v(TAG, "Remote exception in isFingerprintHardwareDetected(): ", e); } } else { Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!"); } return false; } /** * Retrieves the authenticator token for binding keys to the lifecycle * of the current set of fingerprints. Used only by internal clients. * * @hide */ public long getAuthenticatorId() { if (mService != null) { try { return mService.getAuthenticatorId(mContext.getOpPackageName()); } catch (RemoteException e) { Log.v(TAG, "Remote exception in getAuthenticatorId(): ", e); } } else { Log.w(TAG, "getAuthenticatorId(): Service not connected!"); } return 0; } private class MyHandler extends Handler { private MyHandler(Context context) { super(context.getMainLooper()); } private MyHandler(Looper looper) { super(looper); } public void handleMessage(android.os.Message msg) { switch(msg.what) { case MSG_ENROLL_RESULT: sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */); break; case MSG_ACQUIRED: sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */); break; case MSG_AUTHENTICATION_SUCCEEDED: sendAuthenticatedSucceeded((Fingerprint) msg.obj); break; case MSG_AUTHENTICATION_FAILED: sendAuthenticatedFailed(); break; case MSG_ERROR: sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */); break; case MSG_REMOVED: sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */, msg.arg2 /* groupId */); } } private void sendRemovedResult(long deviceId, int fingerId, int groupId) { if (mRemovalCallback != null) { int reqFingerId = mRemovalFingerprint.getFingerId(); int reqGroupId = mRemovalFingerprint.getGroupId(); if (fingerId != reqFingerId) { Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId); } if (fingerId != reqFingerId) { Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId); } mRemovalCallback.onRemovalSucceeded(mRemovalFingerprint); } } private void sendErrorResult(long deviceId, int errMsgId) { if (mEnrollmentCallback != null) { mEnrollmentCallback.onEnrollmentError(errMsgId, getErrorString(errMsgId)); } else if (mAuthenticationCallback != null) { mAuthenticationCallback.onAuthenticationError(errMsgId, getErrorString(errMsgId)); } else if (mRemovalCallback != null) { mRemovalCallback.onRemovalError(mRemovalFingerprint, errMsgId, getErrorString(errMsgId)); } } private void sendEnrollResult(Fingerprint fp, int remaining) { if (mEnrollmentCallback != null) { mEnrollmentCallback.onEnrollmentProgress(remaining); } } private void sendAuthenticatedSucceeded(Fingerprint fp) { if (mAuthenticationCallback != null) { final AuthenticationResult result = new AuthenticationResult(mCryptoObject, fp); mAuthenticationCallback.onAuthenticationSucceeded(result); } } private void sendAuthenticatedFailed() { if (mAuthenticationCallback != null) { mAuthenticationCallback.onAuthenticationFailed(); } } private void sendAcquiredResult(long deviceId, int acquireInfo) { if (mAuthenticationCallback != null) { mAuthenticationCallback.onAuthenticationAcquired(acquireInfo); } final String msg = getAcquiredString(acquireInfo); if (msg == null) { return; } if (mEnrollmentCallback != null) { mEnrollmentCallback.onEnrollmentHelp(acquireInfo, msg); } else if (mAuthenticationCallback != null) { mAuthenticationCallback.onAuthenticationHelp(acquireInfo, msg); } } }; /** * @hide */ public FingerprintManager(Context context, IFingerprintService service) { mContext = context; mService = service; if (mService == null) { Slog.v(TAG, "FingerprintManagerService was null"); } mHandler = new MyHandler(context); } private int getCurrentUserId() { try { return ActivityManagerNative.getDefault().getCurrentUser().id; } catch (RemoteException e) { Log.w(TAG, "Failed to get current user id\n"); return UserHandle.USER_NULL; } } private void cancelEnrollment() { if (mService != null) try { mService.cancelEnrollment(mToken); } catch (RemoteException e) { if (DEBUG) Log.w(TAG, "Remote exception while canceling enrollment"); } } private void cancelAuthentication(CryptoObject cryptoObject) { if (mService != null) try { mService.cancelAuthentication(mToken, mContext.getOpPackageName()); } catch (RemoteException e) { if (DEBUG) Log.w(TAG, "Remote exception while canceling enrollment"); } } private String getErrorString(int errMsg) { switch (errMsg) { case FINGERPRINT_ERROR_UNABLE_TO_PROCESS: return mContext.getString( com.android.internal.R.string.fingerprint_error_unable_to_process); case FINGERPRINT_ERROR_HW_UNAVAILABLE: return mContext.getString( com.android.internal.R.string.fingerprint_error_hw_not_available); case FINGERPRINT_ERROR_NO_SPACE: return mContext.getString( com.android.internal.R.string.fingerprint_error_no_space); case FINGERPRINT_ERROR_TIMEOUT: return mContext.getString(com.android.internal.R.string.fingerprint_error_timeout); case FINGERPRINT_ERROR_CANCELED: return mContext.getString(com.android.internal.R.string.fingerprint_error_canceled); case FINGERPRINT_ERROR_LOCKOUT: return mContext.getString(com.android.internal.R.string.fingerprint_error_lockout); default: if (errMsg >= FINGERPRINT_ERROR_VENDOR_BASE) { int msgNumber = errMsg - FINGERPRINT_ERROR_VENDOR_BASE; String[] msgArray = mContext.getResources().getStringArray( com.android.internal.R.array.fingerprint_error_vendor); if (msgNumber < msgArray.length) { return msgArray[msgNumber]; } } return null; } } private String getAcquiredString(int acquireInfo) { switch (acquireInfo) { case FINGERPRINT_ACQUIRED_GOOD: return null; case FINGERPRINT_ACQUIRED_PARTIAL: return mContext.getString( com.android.internal.R.string.fingerprint_acquired_partial); case FINGERPRINT_ACQUIRED_INSUFFICIENT: return mContext.getString( com.android.internal.R.string.fingerprint_acquired_insufficient); case FINGERPRINT_ACQUIRED_IMAGER_DIRTY: return mContext.getString( com.android.internal.R.string.fingerprint_acquired_imager_dirty); case FINGERPRINT_ACQUIRED_TOO_SLOW: return mContext.getString( com.android.internal.R.string.fingerprint_acquired_too_slow); case FINGERPRINT_ACQUIRED_TOO_FAST: return mContext.getString( com.android.internal.R.string.fingerprint_acquired_too_fast); default: if (acquireInfo >= FINGERPRINT_ACQUIRED_VENDOR_BASE) { int msgNumber = acquireInfo - FINGERPRINT_ACQUIRED_VENDOR_BASE; String[] msgArray = mContext.getResources().getStringArray( com.android.internal.R.array.fingerprint_acquired_vendor); if (msgNumber < msgArray.length) { return msgArray[msgNumber]; } } return null; } } private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() { @Override // binder call public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) { mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0, new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget(); } @Override // binder call public void onAcquired(long deviceId, int acquireInfo) { mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget(); } @Override // binder call public void onAuthenticationSucceeded(long deviceId, Fingerprint fp) { mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, fp).sendToTarget(); } @Override // binder call public void onAuthenticationFailed(long deviceId) { mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();; } @Override // binder call public void onError(long deviceId, int error) { mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget(); } @Override // binder call public void onRemoved(long deviceId, int fingerId, int groupId) { mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget(); } };}
IFingerprintDaemon.aidl
/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package android.hardware.fingerprint;import android.hardware.fingerprint.IFingerprintDaemonCallback;/** * Communication channel from FingerprintService to FingerprintDaemon (fingerprintd) * @hide */interface IFingerprintDaemon { int authenticate(long sessionId, int groupId); int cancelAuthentication(); int enroll(in byte [] token, int groupId, int timeout); int cancelEnrollment(); long preEnroll(); int remove(int fingerId, int groupId); long getAuthenticatorId(); int setActiveGroup(int groupId, in byte[] path); long openHal(); int closeHal(); void init(IFingerprintDaemonCallback callback); int postEnroll();}
IFingerprintDaemonCallback.aidl
/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package android.hardware.fingerprint;/** * Communication channel from the fingerprintd back to FingerprintService. * @hide */ interface IFingerprintDaemonCallback { void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining); void onAcquired(long deviceId, int acquiredInfo); void onAuthenticated(long deviceId, int fingerId, int groupId); void onError(long deviceId, int error); void onRemoved(long deviceId, int fingerId, int groupId); void onEnumerate(long deviceId, in int [] fingerIds, in int [] groupIds);}
IFingerprintService.aidl
/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package android.hardware.fingerprint;import android.os.Bundle;import android.hardware.fingerprint.IFingerprintServiceReceiver;import android.hardware.fingerprint.Fingerprint;import java.util.List;/** * Communication channel from client to the fingerprint service. * @hide */interface IFingerprintService { // Authenticate the given sessionId with a fingerprint void authenticate(IBinder token, long sessionId, int userId, IFingerprintServiceReceiver receiver, int flags, String opPackageName); // Cancel authentication for the given sessionId void cancelAuthentication(IBinder token, String opPackageName); // Start fingerprint enrollment void enroll(IBinder token, in byte [] cryptoToken, int groupId, IFingerprintServiceReceiver receiver, int flags); // Cancel enrollment in progress void cancelEnrollment(IBinder token); // Any errors resulting from this call will be returned to the listener void remove(IBinder token, int fingerId, int groupId, IFingerprintServiceReceiver receiver); // Rename the fingerprint specified by fingerId and groupId to the given name void rename(int fingerId, int groupId, String name); // Get a list of enrolled fingerprints in the given group. List getEnrolledFingerprints(int groupId, String opPackageName); // Determine if HAL is loaded and ready boolean isHardwareDetected(long deviceId, String opPackageName); // Get a pre-enrollment authentication token long preEnroll(IBinder token); // Finish an enrollment sequence and invalidate the authentication token int postEnroll(IBinder token); // Determine if a user has at least one enrolled fingerprint boolean hasEnrolledFingerprints(int groupId, String opPackageName); // Gets the number of hardware devices // int getHardwareDeviceCount(); // Gets the unique device id for hardware enumerated at i // long getHardwareDevice(int i); // Gets the authenticator ID for fingerprint long getAuthenticatorId(String opPackageName);}
IFingerprintServiceReceiver.aidl
/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package android.hardware.fingerprint;import android.hardware.fingerprint.Fingerprint;import android.os.Bundle;import android.os.UserHandle;/** * Communication channel from the FingerprintService back to FingerprintManager. * @hide */oneway interface IFingerprintServiceReceiver { void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining); void onAcquired(long deviceId, int acquiredInfo); void onAuthenticationSucceeded(long deviceId, in Fingerprint fp); void onAuthenticationFailed(long deviceId); void onError(long deviceId, int error); void onRemoved(long deviceId, int fingerId, int groupId);}
/system/core/fingerprintd/
-------------------------------------------------------------------------------------------
Android.mk
## Copyright (C) 2015 The Android Open Source Project## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.#LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)#LOCAL_MULTILIB :=32 #test bruce LOCAL_CFLAGS := -Wall -Wextra -Werror -WunusedLOCAL_SRC_FILES := \FingerprintDaemonProxy.cpp \IFingerprintDaemon.cpp \IFingerprintDaemonCallback.cpp \fingerprintd.cppLOCAL_MODULE := fingerprintdLOCAL_SHARED_LIBRARIES := \libbinder \liblog \libhardware \libutils \libkeystore_binderinclude $(BUILD_EXECUTABLE)
fingerprintd.cpp
/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#define LOG_TAG "fingerprintd"#include #include #include #include #include #include #include #include // for error codes#include #include #include #include "FingerprintDaemonProxy.h"int main() { ALOGI("Starting " LOG_TAG); android::sp serviceManager = android::defaultServiceManager(); android::sp proxy = android::FingerprintDaemonProxy::getInstance(); android::status_t ret = serviceManager->addService( android::FingerprintDaemonProxy::descriptor, proxy); if (ret != android::OK) { ALOGE("Couldn't register " LOG_TAG " binder service!"); return -1; } /* * We're the only thread in existence, so we're just going to process * Binder transaction as a single-threaded program. */ android::IPCThreadState::self()->joinThreadPool(); ALOGI("Done"); return 0;}
FingerprintDaemonProxy.cpp
/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#define LOG_TAG "fingerprintd"#include #include #include #include #include #include // for error codes#include #include "FingerprintDaemonProxy.h"#include #include #include namespace android {FingerprintDaemonProxy* FingerprintDaemonProxy::sInstance = NULL;// Supported fingerprint HAL versionstatic const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(2, 0);FingerprintDaemonProxy::FingerprintDaemonProxy() : mModule(NULL), mDevice(NULL), mCallback(NULL) {}FingerprintDaemonProxy::~FingerprintDaemonProxy() { closeHal();}void FingerprintDaemonProxy::hal_notify_callback(const fingerprint_msg_t *msg) { FingerprintDaemonProxy* instance = FingerprintDaemonProxy::getInstance(); const sp callback = instance->mCallback; if (callback == NULL) { ALOGE("Invalid callback object"); return; } const int64_t device = (int64_t) instance->mDevice; switch (msg->type) { case FINGERPRINT_ERROR: ALOGD("onError(%d)", msg->data.error); callback->onError(device, msg->data.error); break; case FINGERPRINT_ACQUIRED: ALOGD("onAcquired(%d)", msg->data.acquired.acquired_info); callback->onAcquired(device, msg->data.acquired.acquired_info); break; case FINGERPRINT_AUTHENTICATED: ALOGD("onAuthenticated(fid=%d, gid=%d)", msg->data.authenticated.finger.fid, msg->data.authenticated.finger.gid); if (msg->data.authenticated.finger.fid != 0) { const uint8_t* hat = reinterpret_cast(&msg->data.authenticated.hat); instance->notifyKeystore(hat, sizeof(msg->data.authenticated.hat)); } callback->onAuthenticated(device, msg->data.authenticated.finger.fid, msg->data.authenticated.finger.gid); break; case FINGERPRINT_TEMPLATE_ENROLLING: ALOGD("onEnrollResult(fid=%d, gid=%d, rem=%d)", msg->data.enroll.finger.fid, msg->data.enroll.finger.gid, msg->data.enroll.samples_remaining); callback->onEnrollResult(device, msg->data.enroll.finger.fid, msg->data.enroll.finger.gid, msg->data.enroll.samples_remaining); break; case FINGERPRINT_TEMPLATE_REMOVED: ALOGD("onRemove(fid=%d, gid=%d)", msg->data.removed.finger.fid, msg->data.removed.finger.gid); callback->onRemoved(device, msg->data.removed.finger.fid, msg->data.removed.finger.gid); break; default: ALOGE("invalid msg type: %d", msg->type); return; }}void FingerprintDaemonProxy::notifyKeystore(const uint8_t *auth_token, const size_t auth_token_length) { if (auth_token != NULL && auth_token_length > 0) { // TODO: cache service? sp < IServiceManager > sm = defaultServiceManager(); sp < IBinder > binder = sm->getService(String16("android.security.keystore")); sp < IKeystoreService > service = interface_cast < IKeystoreService > (binder); if (service != NULL) { status_t ret = service->addAuthToken(auth_token, auth_token_length); if (ret != ResponseCode::NO_ERROR) { ALOGE("Falure sending auth token to KeyStore: %d", ret); } } else { ALOGE("Unable to communicate with KeyStore"); } }}void FingerprintDaemonProxy::init(const sp& callback) { if (mCallback != NULL && IInterface::asBinder(callback) != IInterface::asBinder(mCallback)) { IInterface::asBinder(mCallback)->unlinkToDeath(this); } IInterface::asBinder(callback)->linkToDeath(this); mCallback = callback;}int32_t FingerprintDaemonProxy::enroll(const uint8_t* token, ssize_t tokenSize, int32_t groupId, int32_t timeout) { ALOG(LOG_VERBOSE, LOG_TAG, "enroll(gid=%d, timeout=%d)\n", groupId, timeout); if (tokenSize != sizeof(hw_auth_token_t) ) { ALOG(LOG_VERBOSE, LOG_TAG, "enroll() : invalid token size %zu\n", tokenSize); return -1; } const hw_auth_token_t* authToken = reinterpret_cast(token); return mDevice->enroll(mDevice, authToken, groupId, timeout);}uint64_t FingerprintDaemonProxy::preEnroll() { return mDevice->pre_enroll(mDevice);}int32_t FingerprintDaemonProxy::postEnroll() { return mDevice->post_enroll(mDevice);}int32_t FingerprintDaemonProxy::stopEnrollment() { ALOG(LOG_VERBOSE, LOG_TAG, "stopEnrollment()\n"); return mDevice->cancel(mDevice);}int32_t FingerprintDaemonProxy::authenticate(uint64_t sessionId, uint32_t groupId) { ALOG(LOG_VERBOSE, LOG_TAG, "authenticate(sid=%" PRId64 ", gid=%d)\n", sessionId, groupId); return mDevice->authenticate(mDevice, sessionId, groupId);}int32_t FingerprintDaemonProxy::stopAuthentication() { ALOG(LOG_VERBOSE, LOG_TAG, "stopAuthentication()\n"); return mDevice->cancel(mDevice);}int32_t FingerprintDaemonProxy::remove(int32_t fingerId, int32_t groupId) { ALOG(LOG_VERBOSE, LOG_TAG, "remove(fid=%d, gid=%d)\n", fingerId, groupId); return mDevice->remove(mDevice, groupId, fingerId);}uint64_t FingerprintDaemonProxy::getAuthenticatorId() { return mDevice->get_authenticator_id(mDevice);}int32_t FingerprintDaemonProxy::setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathlen) { if (pathlen >= PATH_MAX || pathlen <= 0) { ALOGE("Bad path length: %zd", pathlen); return -1; } // Convert to null-terminated string char path_name[PATH_MAX]; memcpy(path_name, path, pathlen); path_name[pathlen] = '\0'; ALOG(LOG_VERBOSE, LOG_TAG, "setActiveGroup(%d, %s, %zu)", groupId, path_name, pathlen); return mDevice->set_active_group(mDevice, groupId, path_name);}//add bruce/*typedef struct vendor_fingerprint{ const char * vendor; const char * dev_node; const char * lib_name;}vendor_fingerprint_t;#define VENDOR_LIST_COUNT 2vendor_fingerprint_t vendor_list[VENDOR_LIST_COUNT]={ {"sunwave","/dev/sunwave_fp","sunwave.fingerprint"}, {"mas","/dev/madev0","fingerprint"},//mas.fingerprint};*///end bruceint64_t FingerprintDaemonProxy::openHal() { ALOG(LOG_VERBOSE, LOG_TAG, "nativeOpenHal()\n"); int err; //add bruce /* char *sensorId=NULL; vendor_fingerprint_t *vendor; for(int i=0;idev_node,F_OK); if(res==0){ sensorId=(char*)vendor->lib_name; ALOGE("%s find fingerprint vendor %s",__func__,vendor->vendor); break; } } if(sensorId==NULL){ ALOGE("Cant't find fingerprint vendor"); return 0; }*///end bruce const hw_module_t *hw_module = NULL;// if (0 != (err = hw_get_module(sensorId, &hw_module))) {//FINGERPRINT_HARDWARE_MODULE_ID test bruce if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_module))) { ALOGE("Can't open fingerprint HW Module, error: %d", err); return 0; } if (NULL == hw_module) { ALOGE("No valid fingerprint module"); return 0; } mModule = reinterpret_cast(hw_module); if (mModule->common.methods->open == NULL) { ALOGE("No valid open method"); return 0; } hw_device_t *device = NULL; if (0 != (err = mModule->common.methods->open(hw_module, NULL, &device))) { ALOGE("Can't open fingerprint methods, error: %d", err); return 0; } if (kVersion != device->version) { ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version); // return 0; // FIXME } mDevice = reinterpret_cast(device); err = mDevice->set_notify(mDevice, hal_notify_callback); if (err < 0) { ALOGE("Failed in call to set_notify(), err=%d", err); return 0; } // Sanity check - remove if (mDevice->notify != hal_notify_callback) { ALOGE("NOTIFY not set properly: %p != %p", mDevice->notify, hal_notify_callback); } ALOG(LOG_VERBOSE, LOG_TAG, "fingerprint HAL successfully initialized"); return reinterpret_cast(mDevice); // This is just a handle}int32_t FingerprintDaemonProxy::closeHal() { ALOG(LOG_VERBOSE, LOG_TAG, "nativeCloseHal()\n"); if (mDevice == NULL) { ALOGE("No valid device"); return -ENOSYS; } int err; if (0 != (err = mDevice->common.close(reinterpret_cast(mDevice)))) { ALOGE("Can't close fingerprint module, error: %d", err); return err; } mDevice = NULL; return 0;}void FingerprintDaemonProxy::binderDied(const wp& who) { ALOGD("binder died"); int err; if (0 != (err = closeHal())) { ALOGE("Can't close fingerprint device, error: %d", err); } if (IInterface::asBinder(mCallback) == who) { mCallback = NULL; }}}
FingerprintDaemonRroxy.h
/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#ifndef FINGERPRINT_DAEMON_PROXY_H_#define FINGERPRINT_DAEMON_PROXY_H_#include "IFingerprintDaemon.h"#include "IFingerprintDaemonCallback.h"namespace android {class FingerprintDaemonProxy : public BnFingerprintDaemon { public: static FingerprintDaemonProxy* getInstance() { if (sInstance == NULL) { sInstance = new FingerprintDaemonProxy(); } return sInstance; } // These reflect binder methods. virtual void init(const sp& callback); virtual int32_t enroll(const uint8_t* token, ssize_t tokenLength, int32_t groupId, int32_t timeout); virtual uint64_t preEnroll(); virtual int32_t postEnroll(); virtual int32_t stopEnrollment(); virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId); virtual int32_t stopAuthentication(); virtual int32_t remove(int32_t fingerId, int32_t groupId); virtual uint64_t getAuthenticatorId(); virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen); virtual int64_t openHal(); virtual int32_t closeHal(); private: FingerprintDaemonProxy(); virtual ~FingerprintDaemonProxy(); void binderDied(const wp& who); void notifyKeystore(const uint8_t *auth_token, const size_t auth_token_length); static void hal_notify_callback(const fingerprint_msg_t *msg); static FingerprintDaemonProxy* sInstance; fingerprint_module_t const* mModule; fingerprint_device_t* mDevice; sp mCallback;};} // namespace android#endif // FINGERPRINT_DAEMON_PROXY_H_
FingerprintDaemon.cpp
/* * Copyright 2015, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License.*/#include #include #include #include #include #include #include #include // for error code#include #include #include #include "IFingerprintDaemon.h"#include "IFingerprintDaemonCallback.h"namespace android {static const String16 USE_FINGERPRINT_PERMISSION("android.permission.USE_FINGERPRINT");static const String16 MANAGE_FINGERPRINT_PERMISSION("android.permission.MANAGE_FINGERPRINT");static const String16 HAL_FINGERPRINT_PERMISSION("android.permission.MANAGE_FINGERPRINT"); // TODOstatic const String16 DUMP_PERMISSION("android.permission.DUMP");const android::String16IFingerprintDaemon::descriptor("android.hardware.fingerprint.IFingerprintDaemon");const android::String16&IFingerprintDaemon::getInterfaceDescriptor() const { return IFingerprintDaemon::descriptor;}status_t BnFingerprintDaemon::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case AUTHENTICATE: { CHECK_INTERFACE(IFingerprintDaemon, data, reply); if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { return PERMISSION_DENIED; } const uint64_t sessionId = data.readInt64(); const uint32_t groupId = data.readInt32(); const int32_t ret = authenticate(sessionId, groupId); reply->writeNoException(); reply->writeInt32(ret); return NO_ERROR; }; case CANCEL_AUTHENTICATION: { CHECK_INTERFACE(IFingerprintDaemon, data, reply); if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { return PERMISSION_DENIED; } const int32_t ret = stopAuthentication(); reply->writeNoException(); reply->writeInt32(ret); return NO_ERROR; } case ENROLL: { CHECK_INTERFACE(IFingerprintDaemon, data, reply); if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { return PERMISSION_DENIED; } const ssize_t tokenSize = data.readInt32(); const uint8_t* token = static_cast(data.readInplace(tokenSize)); const int32_t groupId = data.readInt32(); const int32_t timeout = data.readInt32(); const int32_t ret = enroll(token, tokenSize, groupId, timeout); reply->writeNoException(); reply->writeInt32(ret); return NO_ERROR; } case CANCEL_ENROLLMENT: { CHECK_INTERFACE(IFingerprintDaemon, data, reply); if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { return PERMISSION_DENIED; } const int32_t ret = stopEnrollment(); reply->writeNoException(); reply->writeInt32(ret); return NO_ERROR; } case PRE_ENROLL: { CHECK_INTERFACE(IFingerprintDaemon, data, reply); if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { return PERMISSION_DENIED; } const uint64_t ret = preEnroll(); reply->writeNoException(); reply->writeInt64(ret); return NO_ERROR; } case POST_ENROLL: { CHECK_INTERFACE(IFingerprintDaemon, data, reply); if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { return PERMISSION_DENIED; } const int32_t ret = postEnroll(); reply->writeNoException(); reply->writeInt32(ret); return NO_ERROR; } case REMOVE: { CHECK_INTERFACE(IFingerprintDaemon, data, reply); if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { return PERMISSION_DENIED; } const int32_t fingerId = data.readInt32(); const int32_t groupId = data.readInt32(); const int32_t ret = remove(fingerId, groupId); reply->writeNoException(); reply->writeInt32(ret); return NO_ERROR; } case GET_AUTHENTICATOR_ID: { CHECK_INTERFACE(IFingerprintDaemon, data, reply); if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { return PERMISSION_DENIED; } const uint64_t ret = getAuthenticatorId(); reply->writeNoException(); reply->writeInt64(ret); return NO_ERROR; } case SET_ACTIVE_GROUP: { CHECK_INTERFACE(IFingerprintDaemon, data, reply); if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { return PERMISSION_DENIED; } const int32_t group = data.readInt32(); const ssize_t pathSize = data.readInt32(); const uint8_t* path = static_cast(data.readInplace(pathSize)); const int32_t ret = setActiveGroup(group, path, pathSize); reply->writeNoException(); reply->writeInt32(ret); return NO_ERROR; } case OPEN_HAL: { CHECK_INTERFACE(IFingerprintDaemon, data, reply); if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { return PERMISSION_DENIED; } const int64_t ret = openHal(); reply->writeNoException(); reply->writeInt64(ret); return NO_ERROR; } case CLOSE_HAL: { CHECK_INTERFACE(IFingerprintDaemon, data, reply); if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { return PERMISSION_DENIED; } const int32_t ret = closeHal(); reply->writeNoException(); reply->writeInt32(ret); return NO_ERROR; } case INIT: { CHECK_INTERFACE(IFingerprintDaemon, data, reply); if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { return PERMISSION_DENIED; } sp callback = interface_cast(data.readStrongBinder()); init(callback); reply->writeNoException(); return NO_ERROR; } default: return BBinder::onTransact(code, data, reply, flags); }};bool BnFingerprintDaemon::checkPermission(const String16& permission) { const IPCThreadState* ipc = IPCThreadState::self(); const int calling_pid = ipc->getCallingPid(); const int calling_uid = ipc->getCallingUid(); return PermissionCache::checkPermission(permission, calling_pid, calling_uid);}}; // namespace android
IFingerprintDaemon.h
/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#ifndef IFINGERPRINT_DAEMON_H_#define IFINGERPRINT_DAEMON_H_#include #include namespace android {class IFingerprintDaemonCallback;/** Abstract base class for native implementation of FingerprintService.** Note: This must be kept manually in sync with IFingerprintDaemon.aidl*/class IFingerprintDaemon : public IInterface, public IBinder::DeathRecipient { public: enum { AUTHENTICATE = IBinder::FIRST_CALL_TRANSACTION + 0, CANCEL_AUTHENTICATION = IBinder::FIRST_CALL_TRANSACTION + 1, ENROLL = IBinder::FIRST_CALL_TRANSACTION + 2, CANCEL_ENROLLMENT = IBinder::FIRST_CALL_TRANSACTION + 3, PRE_ENROLL = IBinder::FIRST_CALL_TRANSACTION + 4, REMOVE = IBinder::FIRST_CALL_TRANSACTION + 5, GET_AUTHENTICATOR_ID = IBinder::FIRST_CALL_TRANSACTION + 6, SET_ACTIVE_GROUP = IBinder::FIRST_CALL_TRANSACTION + 7, OPEN_HAL = IBinder::FIRST_CALL_TRANSACTION + 8, CLOSE_HAL = IBinder::FIRST_CALL_TRANSACTION + 9, INIT = IBinder::FIRST_CALL_TRANSACTION + 10, POST_ENROLL = IBinder::FIRST_CALL_TRANSACTION + 11, }; IFingerprintDaemon() { } virtual ~IFingerprintDaemon() { } virtual const android::String16& getInterfaceDescriptor() const; // Binder interface methods virtual void init(const sp& callback) = 0; virtual int32_t enroll(const uint8_t* token, ssize_t tokenLength, int32_t groupId, int32_t timeout) = 0; virtual uint64_t preEnroll() = 0; virtual int32_t postEnroll() = 0; virtual int32_t stopEnrollment() = 0; virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId) = 0; virtual int32_t stopAuthentication() = 0; virtual int32_t remove(int32_t fingerId, int32_t groupId) = 0; virtual uint64_t getAuthenticatorId() = 0; virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen) = 0; virtual int64_t openHal() = 0; virtual int32_t closeHal() = 0; // DECLARE_META_INTERFACE - C++ client interface not needed static const android::String16 descriptor; static void hal_notify_callback(const fingerprint_msg_t *msg);};// ----------------------------------------------------------------------------class BnFingerprintDaemon: public BnInterface { public: virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); private: bool checkPermission(const String16& permission);};} // namespace android#endif // IFINGERPRINT_DAEMON_H_
IFingerprintDaemonCallback.cpp
/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#define LOG_TAG "IFingerprintDaemonCallback"#include #include #include #include #include "IFingerprintDaemonCallback.h"namespace android {class BpFingerprintDaemonCallback : public BpInterface{public: BpFingerprintDaemonCallback(const sp& impl) : BpInterface(impl) { } virtual status_t onEnrollResult(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) { Parcel data, reply; data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor()); data.writeInt64(devId); data.writeInt32(fpId); data.writeInt32(gpId); data.writeInt32(rem); return remote()->transact(ON_ENROLL_RESULT, data, &reply, IBinder::FLAG_ONEWAY); } virtual status_t onAcquired(int64_t devId, int32_t acquiredInfo) { Parcel data, reply; data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor()); data.writeInt64(devId); data.writeInt32(acquiredInfo); return remote()->transact(ON_ACQUIRED, data, &reply, IBinder::FLAG_ONEWAY); } virtual status_t onAuthenticated(int64_t devId, int32_t fpId, int32_t gpId) { Parcel data, reply; data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor()); data.writeInt64(devId); data.writeInt32(fpId); data.writeInt32(gpId); return remote()->transact(ON_AUTHENTICATED, data, &reply, IBinder::FLAG_ONEWAY); } virtual status_t onError(int64_t devId, int32_t error) { Parcel data, reply; data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor()); data.writeInt64(devId); data.writeInt32(error); return remote()->transact(ON_ERROR, data, &reply, IBinder::FLAG_ONEWAY); } virtual status_t onRemoved(int64_t devId, int32_t fpId, int32_t gpId) { Parcel data, reply; data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor()); data.writeInt64(devId); data.writeInt32(fpId); data.writeInt32(gpId); return remote()->transact(ON_REMOVED, data, &reply, IBinder::FLAG_ONEWAY); } virtual status_t onEnumerate(int64_t devId, const int32_t* fpIds, const int32_t* gpIds, int32_t sz) { Parcel data, reply; data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor()); data.writeInt64(devId); data.writeInt32Array(sz, fpIds); data.writeInt32Array(sz, gpIds); return remote()->transact(ON_ENUMERATE, data, &reply, IBinder::FLAG_ONEWAY); }};IMPLEMENT_META_INTERFACE(FingerprintDaemonCallback, "android.hardware.fingerprint.IFingerprintDaemonCallback");}; // namespace android
IFingerprintDaemonCallback.h
/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#ifndef IFINGERPRINT_DAEMON_CALLBACK_H_#define IFINGERPRINT_DAEMON_CALLBACK_H_#include #include #include #include namespace android {/** Communication channel back to FingerprintService.java*/class IFingerprintDaemonCallback : public IInterface { public: // must be kept in sync with IFingerprintService.aidl enum { ON_ENROLL_RESULT = IBinder::FIRST_CALL_TRANSACTION + 0, ON_ACQUIRED = IBinder::FIRST_CALL_TRANSACTION + 1, ON_AUTHENTICATED = IBinder::FIRST_CALL_TRANSACTION + 2, ON_ERROR = IBinder::FIRST_CALL_TRANSACTION + 3, ON_REMOVED = IBinder::FIRST_CALL_TRANSACTION + 4, ON_ENUMERATE = IBinder::FIRST_CALL_TRANSACTION + 5, }; virtual status_t onEnrollResult(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) = 0; virtual status_t onAcquired(int64_t devId, int32_t acquiredInfo) = 0; virtual status_t onAuthenticated(int64_t devId, int32_t fingerId, int32_t groupId) = 0; virtual status_t onError(int64_t devId, int32_t error) = 0; virtual status_t onRemoved(int64_t devId, int32_t fingerId, int32_t groupId) = 0; virtual status_t onEnumerate(int64_t devId, const int32_t* fpIds, const int32_t* gpIds, int32_t sz) = 0; DECLARE_META_INTERFACE(FingerprintDaemonCallback);};}; // namespace android#endif // IFINGERPRINT_DAEMON_CALLBACK_H_
/hardware/libhardware/include/hardware/fingerprint.h
-------------------------------------------------------------------------------------------
fingerprint.h
/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#ifndef ANDROID_INCLUDE_HARDWARE_FINGERPRINT_H#define ANDROID_INCLUDE_HARDWARE_FINGERPRINT_H#include #define FINGERPRINT_MODULE_API_VERSION_1_0 HARDWARE_MODULE_API_VERSION(1, 0)#define FINGERPRINT_MODULE_API_VERSION_2_0 HARDWARE_MODULE_API_VERSION(2, 0)#define FINGERPRINT_HARDWARE_MODULE_ID "fingerprint"typedef enum fingerprint_msg_type { FINGERPRINT_ERROR = -1, FINGERPRINT_ACQUIRED = 1, FINGERPRINT_TEMPLATE_ENROLLING = 3, FINGERPRINT_TEMPLATE_REMOVED = 4, FINGERPRINT_AUTHENTICATED = 5} fingerprint_msg_type_t;/* * Fingerprint errors are meant to tell the framework to terminate the current operation and ask * for the user to correct the situation. These will almost always result in messaging and user * interaction to correct the problem. * * For example, FINGERPRINT_ERROR_CANCELED should follow any acquisition message that results in * a situation where the current operation can't continue without user interaction. For example, * if the sensor is dirty during enrollment and no further enrollment progress can be made, * send FINGERPRINT_ACQUIRED_IMAGER_DIRTY followed by FINGERPRINT_ERROR_CANCELED. */typedef enum fingerprint_error { FINGERPRINT_ERROR_HW_UNAVAILABLE = 1, /* The hardware has an error that can't be resolved. */ FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2, /* Bad data; operation can't continue */ FINGERPRINT_ERROR_TIMEOUT = 3, /* The operation has timed out waiting for user input. */ FINGERPRINT_ERROR_NO_SPACE = 4, /* No space available to store a template */ FINGERPRINT_ERROR_CANCELED = 5, /* The current operation can't proceed. See above. */ FINGERPRINT_ERROR_UNABLE_TO_REMOVE = 6, /* fingerprint with given id can't be removed */ FINGERPRINT_ERROR_VENDOR_BASE = 1000 /* vendor-specific error messages start here */} fingerprint_error_t;/* * Fingerprint acquisition info is meant as feedback for the current operation. Anything but * FINGERPRINT_ACQUIRED_GOOD will be shown to the user as feedback on how to take action on the * current operation. For example, FINGERPRINT_ACQUIRED_IMAGER_DIRTY can be used to tell the user * to clean the sensor. If this will cause the current operation to fail, an additional * FINGERPRINT_ERROR_CANCELED can be sent to stop the operation in progress (e.g. enrollment). * In general, these messages will result in a "Try again" message. */typedef enum fingerprint_acquired_info { FINGERPRINT_ACQUIRED_GOOD = 0, FINGERPRINT_ACQUIRED_PARTIAL = 1, /* sensor needs more data, i.e. longer swipe. */ FINGERPRINT_ACQUIRED_INSUFFICIENT = 2, /* image doesn't contain enough detail for recognition*/ FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3, /* sensor needs to be cleaned */ FINGERPRINT_ACQUIRED_TOO_SLOW = 4, /* mostly swipe-type sensors; not enough data collected */ FINGERPRINT_ACQUIRED_TOO_FAST = 5, /* for swipe and area sensors; tell user to slow down*/ FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000 /* vendor-specific acquisition messages start here */} fingerprint_acquired_info_t;typedef struct fingerprint_finger_id { uint32_t gid; uint32_t fid;} fingerprint_finger_id_t;typedef struct fingerprint_enroll { fingerprint_finger_id_t finger; /* samples_remaining goes from N (no data collected, but N scans needed) * to 0 (no more data is needed to build a template). */ uint32_t samples_remaining; uint64_t msg; /* Vendor specific message. Used for user guidance */} fingerprint_enroll_t;typedef struct fingerprint_removed { fingerprint_finger_id_t finger;} fingerprint_removed_t;typedef struct fingerprint_acquired { fingerprint_acquired_info_t acquired_info; /* information about the image */} fingerprint_acquired_t;typedef struct fingerprint_authenticated { fingerprint_finger_id_t finger; hw_auth_token_t hat;} fingerprint_authenticated_t;typedef struct fingerprint_msg { fingerprint_msg_type_t type; union { fingerprint_error_t error; fingerprint_enroll_t enroll; fingerprint_removed_t removed; fingerprint_acquired_t acquired; fingerprint_authenticated_t authenticated; } data;} fingerprint_msg_t;/* Callback function type */typedef void (*fingerprint_notify_t)(const fingerprint_msg_t *msg);/* Synchronous operation */typedef struct fingerprint_device { /** * Common methods of the fingerprint device. This *must* be the first member * of fingerprint_device as users of this structure will cast a hw_device_t * to fingerprint_device pointer in contexts where it's known * the hw_device_t references a fingerprint_device. */ struct hw_device_t common; /* * Client provided callback function to receive notifications. * Do not set by hand, use the function above instead. */ fingerprint_notify_t notify; /* * Set notification callback: * Registers a user function that would receive notifications from the HAL * The call will block if the HAL state machine is in busy state until HAL * leaves the busy state. * * Function return: 0 if callback function is successfuly registered * or a negative number in case of error, generally from the errno.h set. */ int (*set_notify)(struct fingerprint_device *dev, fingerprint_notify_t notify); /* * Fingerprint pre-enroll enroll request: * Generates a unique token to upper layers to indicate the start of an enrollment transaction. * This token will be wrapped by security for verification and passed to enroll() for * verification before enrollment will be allowed. This is to ensure adding a new fingerprint * template was preceded by some kind of credential confirmation (e.g. device password). * * Function return: 0 if function failed * otherwise, a uint64_t of token */ uint64_t (*pre_enroll)(struct fingerprint_device *dev); /* * Fingerprint enroll request: * Switches the HAL state machine to collect and store a new fingerprint * template. Switches back as soon as enroll is complete * (fingerprint_msg.type == FINGERPRINT_TEMPLATE_ENROLLING && * fingerprint_msg.data.enroll.samples_remaining == 0) * or after timeout_sec seconds. * The fingerprint template will be assigned to the group gid. User has a choice * to supply the gid or set it to 0 in which case a unique group id will be generated. * * Function return: 0 if enrollment process can be successfully started * or a negative number in case of error, generally from the errno.h set. * A notify() function may be called indicating the error condition. */ int (*enroll)(struct fingerprint_device *dev, const hw_auth_token_t *hat, uint32_t gid, uint32_t timeout_sec); /* * Finishes the enroll operation and invalidates the pre_enroll() generated challenge. * This will be called at the end of a multi-finger enrollment session to indicate * that no more fingers will be added. * * Function return: 0 if the request is accepted * or a negative number in case of error, generally from the errno.h set. */ int (*post_enroll)(struct fingerprint_device *dev); /* * get_authenticator_id: * Returns a token associated with the current fingerprint set. This value will * change whenever a new fingerprint is enrolled, thus creating a new fingerprint * set. * * Function return: current authenticator id or 0 if function failed. */ uint64_t (*get_authenticator_id)(struct fingerprint_device *dev); /* * Cancel pending enroll or authenticate, sending FINGERPRINT_ERROR_CANCELED * to all running clients. Switches the HAL state machine back to the idle state. * Unlike enroll_done() doesn't invalidate the pre_enroll() challenge. * * Function return: 0 if cancel request is accepted * or a negative number in case of error, generally from the errno.h set. */ int (*cancel)(struct fingerprint_device *dev); /* * Enumerate all the fingerprint templates found in the directory set by * set_active_group() * This is a synchronous call. The function takes: * - A pointer to an array of fingerprint_finger_id_t. * - The size of the array provided, in fingerprint_finger_id_t elements. * Max_size is a bi-directional parameter and returns the actual number * of elements copied to the caller supplied array. * In the absence of errors the function returns the total number of templates * in the user directory. * If the caller has no good guess on the size of the array he should call this * function witn *max_size == 0 and use the return value for the array allocation. * The caller of this function has a complete list of the templates when *max_size * is the same as the function return. * * Function return: Total number of fingerprint templates in the current storage directory. * or a negative number in case of error, generally from the errno.h set. */ int (*enumerate)(struct fingerprint_device *dev, fingerprint_finger_id_t *results, uint32_t *max_size); /* * Fingerprint remove request: * Deletes a fingerprint template. * Works only within a path set by set_active_group(). * notify() will be called with details on the template deleted. * fingerprint_msg.type == FINGERPRINT_TEMPLATE_REMOVED and * fingerprint_msg.data.removed.id indicating the template id removed. * * Function return: 0 if fingerprint template(s) can be successfully deleted * or a negative number in case of error, generally from the errno.h set. */ int (*remove)(struct fingerprint_device *dev, uint32_t gid, uint32_t fid); /* * Restricts the HAL operation to a set of fingerprints belonging to a * group provided. * The caller must provide a path to a storage location within the user's * data directory. * * Function return: 0 on success * or a negative number in case of error, generally from the errno.h set. */ int (*set_active_group)(struct fingerprint_device *dev, uint32_t gid, const char *store_path); /* * Authenticates an operation identifed by operation_id * * Function return: 0 on success * or a negative number in case of error, generally from the errno.h set. */ int (*authenticate)(struct fingerprint_device *dev, uint64_t operation_id, uint32_t gid); /* Reserved for backward binary compatibility */ void *reserved[4];} fingerprint_device_t;typedef struct fingerprint_module { /** * Common methods of the fingerprint module. This *must* be the first member * of fingerprint_module as users of this structure will cast a hw_module_t * to fingerprint_module pointer in contexts where it's known * the hw_module_t references a fingerprint_module. */ struct hw_module_t common;} fingerprint_module_t;#endif /* ANDROID_INCLUDE_HARDWARE_FINGERPRINT_H */
/hardware/libhardware/modules/fingerprint/fingerprint.c
-------------------------------------------------------------------------------------------
/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#define LOG_TAG "FingerprintHal"#include #include #include #include #include #include static int fingerprint_close(hw_device_t *dev){ if (dev) { free(dev); return 0; } else { return -1; }}static uint64_t fingerprint_pre_enroll(struct fingerprint_device __unused *dev) { return FINGERPRINT_ERROR;}static int fingerprint_enroll(struct fingerprint_device __unused *dev, const hw_auth_token_t __unused *hat, uint32_t __unused gid, uint32_t __unused timeout_sec) { return FINGERPRINT_ERROR;}static uint64_t fingerprint_get_auth_id(struct fingerprint_device __unused *dev) { return FINGERPRINT_ERROR;}static int fingerprint_cancel(struct fingerprint_device __unused *dev) { return FINGERPRINT_ERROR;}static int fingerprint_remove(struct fingerprint_device __unused *dev, uint32_t __unused gid, uint32_t __unused fid) { return FINGERPRINT_ERROR;}static int fingerprint_set_active_group(struct fingerprint_device __unused *dev, uint32_t __unused gid, const char __unused *store_path) { return FINGERPRINT_ERROR;}static int fingerprint_authenticate(struct fingerprint_device __unused *dev, uint64_t __unused operation_id, __unused uint32_t gid) { return FINGERPRINT_ERROR;}static int set_notify_callback(struct fingerprint_device *dev, fingerprint_notify_t notify) { /* Decorate with locks */ dev->notify = notify; return FINGERPRINT_ERROR;}static int fingerprint_open(const hw_module_t* module, const char __unused *id, hw_device_t** device){ if (device == NULL) { ALOGE("NULL device on open"); return -EINVAL; } fingerprint_device_t *dev = malloc(sizeof(fingerprint_device_t)); memset(dev, 0, sizeof(fingerprint_device_t)); dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = FINGERPRINT_MODULE_API_VERSION_2_0; dev->common.module = (struct hw_module_t*) module; dev->common.close = fingerprint_close; dev->pre_enroll = fingerprint_pre_enroll; dev->enroll = fingerprint_enroll; dev->get_authenticator_id = fingerprint_get_auth_id; dev->cancel = fingerprint_cancel; dev->remove = fingerprint_remove; dev->set_active_group = fingerprint_set_active_group; dev->authenticate = fingerprint_authenticate; dev->set_notify = set_notify_callback; dev->notify = NULL; *device = (hw_device_t*) dev; return 0;}static struct hw_module_methods_t fingerprint_module_methods = { .open = fingerprint_open,};fingerprint_module_t HAL_MODULE_INFO_SYM = { .common = { .tag = HARDWARE_MODULE_TAG, .module_api_version = FINGERPRINT_MODULE_API_VERSION_2_0, .hal_api_version = HARDWARE_HAL_API_VERSION, .id = FINGERPRINT_HARDWARE_MODULE_ID, .name = "Demo Fingerprint HAL", .author = "The Android Open Source Project", .methods = &fingerprint_module_methods, },};
更多相关文章
- android SDK系统图片资源的路径。
- Android P 指纹 Framework
- 2011.09.09 ——— android 2.2 修改安装路径
- 更改Android AVD模拟器创建路径位置的方法
- Android 设备指纹
- Android 存储路径浅析
- android 安卓 开发 图片库获得图片的绝对路径
- 修改 Android AVD 创建路径