Loading services/core/java/com/android/server/fingerprint/EnumerateClient.java +3 −3 Original line number Diff line number Diff line Loading @@ -58,7 +58,7 @@ public abstract class EnumerateClient extends ClientMonitor { public int stop(boolean initiatedByClient) { IBiometricsFingerprint daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "stopAuthentication: no fingerprint HAL!"); Slog.w(TAG, "stopEnumeration: no fingerprint HAL!"); return ERROR_ESRCH; } try { Loading Loading @@ -102,12 +102,12 @@ public abstract class EnumerateClient extends ClientMonitor { @Override public boolean onEnrollResult(int fingerId, int groupId, int rem) { if (DEBUG) Slog.w(TAG, "onEnrollResult() called for enumerate!"); return true; // Invalid for Remove return true; // Invalid for Enumerate. } @Override public boolean onRemoved(int fingerId, int groupId, int remaining) { if (DEBUG) Slog.w(TAG, "onRemoved() called for enumerate!"); return true; // Invalid for Authenticate return true; // Invalid for Enumerate. } } services/core/java/com/android/server/fingerprint/FingerprintService.java +184 −33 Original line number Diff line number Diff line Loading @@ -85,6 +85,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.LinkedList; /** * A service to manage multiple clients that want to access the fingerprint HAL API. Loading @@ -96,6 +97,7 @@ import java.util.concurrent.CopyOnWriteArrayList; public class FingerprintService extends SystemService implements IHwBinder.DeathRecipient { static final String TAG = "FingerprintService"; static final boolean DEBUG = true; private static final boolean CLEANUP_UNUSED_FP = false; private static final String FP_DATA_DIR = "fpdata"; private static final int MSG_USER_SWITCHING = 10; private static final String ACTION_LOCKOUT_RESET = Loading Loading @@ -134,6 +136,20 @@ public class FingerprintService extends SystemService implements IHwBinder.Death private ClientMonitor mPendingClient; private PerformanceStats mPerformanceStats; private IBinder mToken = new Binder(); // used for internal FingerprintService enumeration private LinkedList<Integer> mEnumeratingUserIds = new LinkedList<>(); private ArrayList<UserFingerprint> mUnknownFingerprints = new ArrayList<>(); // hw finterprints private class UserFingerprint { Fingerprint f; int userId; public UserFingerprint(Fingerprint f, int userId) { this.f = f; this.userId = userId; } } // Normal fingerprint authentications are tracked by mPerformanceMap. private HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>(); Loading Loading @@ -185,6 +201,7 @@ public class FingerprintService extends SystemService implements IHwBinder.Death + (mCurrentClient != null ? mCurrentClient.getOwnerString() : "null") + " failed to respond to cancel, starting client " + (mPendingClient != null ? mPendingClient.getOwnerString() : "null")); mCurrentClient = null; startClient(mPendingClient, false); } Loading Loading @@ -239,6 +256,7 @@ public class FingerprintService extends SystemService implements IHwBinder.Death if (mHalDeviceId != 0) { loadAuthenticatorIds(); updateActiveGroup(ActivityManager.getCurrentUser(), null); doFingerprintCleanup(ActivityManager.getCurrentUser()); } else { Slog.w(TAG, "Failed to open Fingerprint HAL!"); MetricsLogger.count(mContext, "fingerprintd_openhal_error", 1); Loading @@ -253,7 +271,6 @@ public class FingerprintService extends SystemService implements IHwBinder.Death // This operation can be expensive, so keep track of the elapsed time. Might need to move to // background if it takes too long. long t = System.currentTimeMillis(); mAuthenticatorIds.clear(); for (UserInfo user : UserManager.get(mContext).getUsers(true /* excludeDying */)) { int userId = getUserOrWorkProfileId(null, user.id); Loading @@ -268,14 +285,88 @@ public class FingerprintService extends SystemService implements IHwBinder.Death } } private void doFingerprintCleanup(int userId) { if (CLEANUP_UNUSED_FP) { resetEnumerateState(); mEnumeratingUserIds.push(userId); enumerateNextUser(); } } private void resetEnumerateState() { if (DEBUG) Slog.v(TAG, "Enumerate cleaning up"); mEnumeratingUserIds.clear(); mUnknownFingerprints.clear(); } private void enumerateNextUser() { int nextUser = mEnumeratingUserIds.getFirst(); updateActiveGroup(nextUser, null); boolean restricted = !hasPermission(MANAGE_FINGERPRINT); if (DEBUG) Slog.v(TAG, "Enumerating user id " + nextUser + " of " + mEnumeratingUserIds.size() + " remaining users"); startEnumerate(mToken, nextUser, null, restricted, true /* internal */); } // Remove unknown fingerprints from hardware private void cleanupUnknownFingerprints() { if (!mUnknownFingerprints.isEmpty()) { Slog.w(TAG, "unknown fingerprint size: " + mUnknownFingerprints.size()); UserFingerprint uf = mUnknownFingerprints.get(0); mUnknownFingerprints.remove(uf); boolean restricted = !hasPermission(MANAGE_FINGERPRINT); updateActiveGroup(uf.userId, null); startRemove(mToken, uf.f.getFingerId(), uf.f.getGroupId(), uf.userId, null, restricted, true /* internal */); } else { resetEnumerateState(); } } protected void handleEnumerate(long deviceId, int fingerId, int groupId, int remaining) { if (DEBUG) Slog.w(TAG, "Enumerate: fid=" + fingerId + ", gid=" + groupId + "rem=" + remaining); // TODO: coordinate names with framework if (DEBUG) Slog.w(TAG, "Enumerate: fid=" + fingerId + ", gid=" + groupId + ", dev=" + deviceId + ", rem=" + remaining); ClientMonitor client = mCurrentClient; if ( !(client instanceof InternalRemovalClient) && !(client instanceof EnumerateClient) ) { return; } client.onEnumerationResult(fingerId, groupId, remaining); // All fingerprints in hardware for this user were enumerated if (remaining == 0) { mEnumeratingUserIds.poll(); if (client instanceof InternalEnumerateClient) { List<Fingerprint> enrolled = ((InternalEnumerateClient) client).getEnumeratedList(); Slog.w(TAG, "Added " + enrolled.size() + " enumerated fingerprints for deletion"); for (Fingerprint f : enrolled) { mUnknownFingerprints.add(new UserFingerprint(f, client.getTargetUserId())); } } removeClient(client); if (!mEnumeratingUserIds.isEmpty()) { enumerateNextUser(); } else if (client instanceof InternalEnumerateClient) { if (DEBUG) Slog.v(TAG, "Finished enumerating all users"); // This will start a chain of InternalRemovalClients cleanupUnknownFingerprints(); } } } protected void handleError(long deviceId, int error, int vendorCode) { ClientMonitor client = mCurrentClient; if (client instanceof InternalRemovalClient || client instanceof InternalEnumerateClient) { resetEnumerateState(); } if (client != null && client.onError(error, vendorCode)) { removeClient(client); } Loading @@ -301,10 +392,20 @@ public class FingerprintService extends SystemService implements IHwBinder.Death } protected void handleRemoved(long deviceId, int fingerId, int groupId, int remaining) { if (DEBUG) Slog.w(TAG, "Removed: fid=" + fingerId + ", gid=" + groupId + ", dev=" + deviceId + ", rem=" + remaining); ClientMonitor client = mCurrentClient; if (client != null && client.onRemoved(fingerId, groupId, remaining)) { removeClient(client); } if (client instanceof InternalRemovalClient && !mUnknownFingerprints.isEmpty()) { cleanupUnknownFingerprints(); } else if (client instanceof InternalRemovalClient){ resetEnumerateState(); } } protected void handleAuthenticated(long deviceId, int fingerId, int groupId, Loading Loading @@ -355,6 +456,7 @@ public class FingerprintService extends SystemService implements IHwBinder.Death void handleUserSwitching(int userId) { updateActiveGroup(userId, null); doFingerprintCleanup(userId); } private void removeClient(ClientMonitor client) { Loading Loading @@ -431,7 +533,15 @@ public class FingerprintService extends SystemService implements IHwBinder.Death ClientMonitor currentClient = mCurrentClient; if (currentClient != null) { if (DEBUG) Slog.v(TAG, "request stop current client " + currentClient.getOwnerString()); if (currentClient instanceof InternalEnumerateClient || currentClient instanceof InternalRemovalClient) { // This condition means we're currently running internal diagnostics to // remove extra fingerprints in the hardware and/or the software // TODO: design an escape hatch in case client never finishes } else { currentClient.stop(initiatedByClient); } mPendingClient = newClient; mHandler.removeCallbacks(mResetClientState); mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT); Loading @@ -448,12 +558,30 @@ public class FingerprintService extends SystemService implements IHwBinder.Death } void startRemove(IBinder token, int fingerId, int groupId, int userId, IFingerprintServiceReceiver receiver, boolean restricted) { IFingerprintServiceReceiver receiver, boolean restricted, boolean internal) { IBiometricsFingerprint daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "startRemove: no fingerprint HAL!"); return; } if (internal) { Context context = getContext(); InternalRemovalClient client = new InternalRemovalClient(context, mHalDeviceId, token, receiver, fingerId, groupId, userId, restricted, context.getOpPackageName()) { @Override public void notifyUserActivity() { } @Override public IBiometricsFingerprint getFingerprintDaemon() { return FingerprintService.this.getFingerprintDaemon(); } }; startClient(client, true); } else { RemovalClient client = new RemovalClient(getContext(), mHalDeviceId, token, receiver, fingerId, groupId, userId, restricted, token.toString()) { @Override Loading @@ -468,14 +596,34 @@ public class FingerprintService extends SystemService implements IHwBinder.Death }; startClient(client, true); } } void startEnumerate(IBinder token, int userId, IFingerprintServiceReceiver receiver, boolean restricted) { IFingerprintServiceReceiver receiver, boolean restricted, boolean internal) { IBiometricsFingerprint daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "startEnumerate: no fingerprint HAL!"); return; } if (internal) { List<Fingerprint> enrolledList = getEnrolledFingerprints(userId); Context context = getContext(); InternalEnumerateClient client = new InternalEnumerateClient(context, mHalDeviceId, token, receiver, userId, userId, restricted, context.getOpPackageName(), enrolledList) { @Override public void notifyUserActivity() { } @Override public IBiometricsFingerprint getFingerprintDaemon() { return FingerprintService.this.getFingerprintDaemon(); } }; startClient(client, true); } else { EnumerateClient client = new EnumerateClient(getContext(), mHalDeviceId, token, receiver, userId, userId, restricted, token.toString()) { @Override Loading @@ -490,6 +638,7 @@ public class FingerprintService extends SystemService implements IHwBinder.Death }; startClient(client, true); } } public List<Fingerprint> getEnrolledFingerprints(int userId) { return mFingerprintUtils.getFingerprintsForUser(mContext, userId); Loading Loading @@ -978,11 +1127,13 @@ public class FingerprintService extends SystemService implements IHwBinder.Death mHandler.post(new Runnable() { @Override public void run() { startRemove(token, fingerId, groupId, userId, receiver, restricted); startRemove(token, fingerId, groupId, userId, receiver, restricted, false /* internal */); } }); } @Override // Binder call public void enumerate(final IBinder token, final int userId, final IFingerprintServiceReceiver receiver) { checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission Loading @@ -990,7 +1141,7 @@ public class FingerprintService extends SystemService implements IHwBinder.Death mHandler.post(new Runnable() { @Override public void run() { startEnumerate(token, userId, receiver, restricted); startEnumerate(token, userId, receiver, restricted, false /* internal */); } }); } Loading services/core/java/com/android/server/fingerprint/InternalEnumerateClient.java 0 → 100644 +94 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 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.hardware.fingerprint.IFingerprintServiceReceiver; import android.os.IBinder; import android.util.Slog; import java.util.ArrayList; import java.util.List; /** * An internal class to help clean up unknown fingerprints in the hardware and software */ public abstract class InternalEnumerateClient extends EnumerateClient { private List<Fingerprint> mEnrolledList; private List<Fingerprint> mEnumeratedList = new ArrayList<>(); // list of fp to delete public InternalEnumerateClient(Context context, long halDeviceId, IBinder token, IFingerprintServiceReceiver receiver, int groupId, int userId, boolean restricted, String owner, List<Fingerprint> enrolledList) { super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner); mEnrolledList = enrolledList; } private void handleEnumeratedFingerprint(int fingerId, int groupId, int remaining) { boolean matched = false; for (int i=0; i<mEnrolledList.size(); i++) { if (mEnrolledList.get(i).getFingerId() == fingerId) { mEnrolledList.remove(i); matched = true; Slog.e(TAG, "Matched fingerprint fid=" + fingerId); break; } } // fingerId 0 means no fingerprints are in hardware if (!matched && fingerId != 0) { Fingerprint fingerprint = new Fingerprint("", groupId, fingerId, getHalDeviceId()); mEnumeratedList.add(fingerprint); } } private void doFingerprintCleanup() { if (mEnrolledList == null) { return; } for (Fingerprint f : mEnrolledList) { Slog.e(TAG, "Internal Enumerate: Removing dangling enrolled fingerprint: " + f.getName() + " " + f.getFingerId() + " " + f.getGroupId() + " " + f.getDeviceId()); FingerprintUtils.getInstance().removeFingerprintIdForUser(getContext(), f.getFingerId(), getTargetUserId()); } mEnrolledList.clear(); } public List<Fingerprint> getEnumeratedList() { return mEnumeratedList; } @Override public boolean onEnumerationResult(int fingerId, int groupId, int remaining) { handleEnumeratedFingerprint(fingerId, groupId, remaining); if (remaining == 0) { doFingerprintCleanup(); } return fingerId == 0; // done when id hits 0 } } services/core/java/com/android/server/fingerprint/InternalRemovalClient.java 0 → 100644 +33 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 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.os.IBinder; import android.hardware.fingerprint.IFingerprintServiceReceiver; import com.android.server.fingerprint.RemovalClient; public abstract class InternalRemovalClient extends RemovalClient { public InternalRemovalClient(Context context, long halDeviceId, IBinder token, IFingerprintServiceReceiver receiver, int fingerId, int groupId, int userId, boolean restricted, String owner) { super(context, halDeviceId, token, receiver, fingerId, groupId, userId, restricted, owner); } } services/core/java/com/android/server/fingerprint/RemovalClient.java +16 −5 Original line number Diff line number Diff line Loading @@ -59,12 +59,23 @@ public abstract class RemovalClient extends ClientMonitor { @Override public int stop(boolean initiatedByClient) { // We don't actually stop remove, but inform the client that the cancel operation succeeded // so we can start the next operation. if (initiatedByClient) { onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED, 0 /* vendorCode */); IBiometricsFingerprint daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "stopRemoval: no fingerprint HAL!"); return ERROR_ESRCH; } return 0; try { final int result = daemon.cancel(); if (result != 0) { Slog.w(TAG, "stopRemoval failed, result=" + result); return result; } if (DEBUG) Slog.w(TAG, "client " + getOwnerString() + " is no longer removing"); } catch (RemoteException e) { Slog.e(TAG, "stopRemoval failed", e); return ERROR_ESRCH; } return 0; // success } /* Loading Loading
services/core/java/com/android/server/fingerprint/EnumerateClient.java +3 −3 Original line number Diff line number Diff line Loading @@ -58,7 +58,7 @@ public abstract class EnumerateClient extends ClientMonitor { public int stop(boolean initiatedByClient) { IBiometricsFingerprint daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "stopAuthentication: no fingerprint HAL!"); Slog.w(TAG, "stopEnumeration: no fingerprint HAL!"); return ERROR_ESRCH; } try { Loading Loading @@ -102,12 +102,12 @@ public abstract class EnumerateClient extends ClientMonitor { @Override public boolean onEnrollResult(int fingerId, int groupId, int rem) { if (DEBUG) Slog.w(TAG, "onEnrollResult() called for enumerate!"); return true; // Invalid for Remove return true; // Invalid for Enumerate. } @Override public boolean onRemoved(int fingerId, int groupId, int remaining) { if (DEBUG) Slog.w(TAG, "onRemoved() called for enumerate!"); return true; // Invalid for Authenticate return true; // Invalid for Enumerate. } }
services/core/java/com/android/server/fingerprint/FingerprintService.java +184 −33 Original line number Diff line number Diff line Loading @@ -85,6 +85,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.LinkedList; /** * A service to manage multiple clients that want to access the fingerprint HAL API. Loading @@ -96,6 +97,7 @@ import java.util.concurrent.CopyOnWriteArrayList; public class FingerprintService extends SystemService implements IHwBinder.DeathRecipient { static final String TAG = "FingerprintService"; static final boolean DEBUG = true; private static final boolean CLEANUP_UNUSED_FP = false; private static final String FP_DATA_DIR = "fpdata"; private static final int MSG_USER_SWITCHING = 10; private static final String ACTION_LOCKOUT_RESET = Loading Loading @@ -134,6 +136,20 @@ public class FingerprintService extends SystemService implements IHwBinder.Death private ClientMonitor mPendingClient; private PerformanceStats mPerformanceStats; private IBinder mToken = new Binder(); // used for internal FingerprintService enumeration private LinkedList<Integer> mEnumeratingUserIds = new LinkedList<>(); private ArrayList<UserFingerprint> mUnknownFingerprints = new ArrayList<>(); // hw finterprints private class UserFingerprint { Fingerprint f; int userId; public UserFingerprint(Fingerprint f, int userId) { this.f = f; this.userId = userId; } } // Normal fingerprint authentications are tracked by mPerformanceMap. private HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>(); Loading Loading @@ -185,6 +201,7 @@ public class FingerprintService extends SystemService implements IHwBinder.Death + (mCurrentClient != null ? mCurrentClient.getOwnerString() : "null") + " failed to respond to cancel, starting client " + (mPendingClient != null ? mPendingClient.getOwnerString() : "null")); mCurrentClient = null; startClient(mPendingClient, false); } Loading Loading @@ -239,6 +256,7 @@ public class FingerprintService extends SystemService implements IHwBinder.Death if (mHalDeviceId != 0) { loadAuthenticatorIds(); updateActiveGroup(ActivityManager.getCurrentUser(), null); doFingerprintCleanup(ActivityManager.getCurrentUser()); } else { Slog.w(TAG, "Failed to open Fingerprint HAL!"); MetricsLogger.count(mContext, "fingerprintd_openhal_error", 1); Loading @@ -253,7 +271,6 @@ public class FingerprintService extends SystemService implements IHwBinder.Death // This operation can be expensive, so keep track of the elapsed time. Might need to move to // background if it takes too long. long t = System.currentTimeMillis(); mAuthenticatorIds.clear(); for (UserInfo user : UserManager.get(mContext).getUsers(true /* excludeDying */)) { int userId = getUserOrWorkProfileId(null, user.id); Loading @@ -268,14 +285,88 @@ public class FingerprintService extends SystemService implements IHwBinder.Death } } private void doFingerprintCleanup(int userId) { if (CLEANUP_UNUSED_FP) { resetEnumerateState(); mEnumeratingUserIds.push(userId); enumerateNextUser(); } } private void resetEnumerateState() { if (DEBUG) Slog.v(TAG, "Enumerate cleaning up"); mEnumeratingUserIds.clear(); mUnknownFingerprints.clear(); } private void enumerateNextUser() { int nextUser = mEnumeratingUserIds.getFirst(); updateActiveGroup(nextUser, null); boolean restricted = !hasPermission(MANAGE_FINGERPRINT); if (DEBUG) Slog.v(TAG, "Enumerating user id " + nextUser + " of " + mEnumeratingUserIds.size() + " remaining users"); startEnumerate(mToken, nextUser, null, restricted, true /* internal */); } // Remove unknown fingerprints from hardware private void cleanupUnknownFingerprints() { if (!mUnknownFingerprints.isEmpty()) { Slog.w(TAG, "unknown fingerprint size: " + mUnknownFingerprints.size()); UserFingerprint uf = mUnknownFingerprints.get(0); mUnknownFingerprints.remove(uf); boolean restricted = !hasPermission(MANAGE_FINGERPRINT); updateActiveGroup(uf.userId, null); startRemove(mToken, uf.f.getFingerId(), uf.f.getGroupId(), uf.userId, null, restricted, true /* internal */); } else { resetEnumerateState(); } } protected void handleEnumerate(long deviceId, int fingerId, int groupId, int remaining) { if (DEBUG) Slog.w(TAG, "Enumerate: fid=" + fingerId + ", gid=" + groupId + "rem=" + remaining); // TODO: coordinate names with framework if (DEBUG) Slog.w(TAG, "Enumerate: fid=" + fingerId + ", gid=" + groupId + ", dev=" + deviceId + ", rem=" + remaining); ClientMonitor client = mCurrentClient; if ( !(client instanceof InternalRemovalClient) && !(client instanceof EnumerateClient) ) { return; } client.onEnumerationResult(fingerId, groupId, remaining); // All fingerprints in hardware for this user were enumerated if (remaining == 0) { mEnumeratingUserIds.poll(); if (client instanceof InternalEnumerateClient) { List<Fingerprint> enrolled = ((InternalEnumerateClient) client).getEnumeratedList(); Slog.w(TAG, "Added " + enrolled.size() + " enumerated fingerprints for deletion"); for (Fingerprint f : enrolled) { mUnknownFingerprints.add(new UserFingerprint(f, client.getTargetUserId())); } } removeClient(client); if (!mEnumeratingUserIds.isEmpty()) { enumerateNextUser(); } else if (client instanceof InternalEnumerateClient) { if (DEBUG) Slog.v(TAG, "Finished enumerating all users"); // This will start a chain of InternalRemovalClients cleanupUnknownFingerprints(); } } } protected void handleError(long deviceId, int error, int vendorCode) { ClientMonitor client = mCurrentClient; if (client instanceof InternalRemovalClient || client instanceof InternalEnumerateClient) { resetEnumerateState(); } if (client != null && client.onError(error, vendorCode)) { removeClient(client); } Loading @@ -301,10 +392,20 @@ public class FingerprintService extends SystemService implements IHwBinder.Death } protected void handleRemoved(long deviceId, int fingerId, int groupId, int remaining) { if (DEBUG) Slog.w(TAG, "Removed: fid=" + fingerId + ", gid=" + groupId + ", dev=" + deviceId + ", rem=" + remaining); ClientMonitor client = mCurrentClient; if (client != null && client.onRemoved(fingerId, groupId, remaining)) { removeClient(client); } if (client instanceof InternalRemovalClient && !mUnknownFingerprints.isEmpty()) { cleanupUnknownFingerprints(); } else if (client instanceof InternalRemovalClient){ resetEnumerateState(); } } protected void handleAuthenticated(long deviceId, int fingerId, int groupId, Loading Loading @@ -355,6 +456,7 @@ public class FingerprintService extends SystemService implements IHwBinder.Death void handleUserSwitching(int userId) { updateActiveGroup(userId, null); doFingerprintCleanup(userId); } private void removeClient(ClientMonitor client) { Loading Loading @@ -431,7 +533,15 @@ public class FingerprintService extends SystemService implements IHwBinder.Death ClientMonitor currentClient = mCurrentClient; if (currentClient != null) { if (DEBUG) Slog.v(TAG, "request stop current client " + currentClient.getOwnerString()); if (currentClient instanceof InternalEnumerateClient || currentClient instanceof InternalRemovalClient) { // This condition means we're currently running internal diagnostics to // remove extra fingerprints in the hardware and/or the software // TODO: design an escape hatch in case client never finishes } else { currentClient.stop(initiatedByClient); } mPendingClient = newClient; mHandler.removeCallbacks(mResetClientState); mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT); Loading @@ -448,12 +558,30 @@ public class FingerprintService extends SystemService implements IHwBinder.Death } void startRemove(IBinder token, int fingerId, int groupId, int userId, IFingerprintServiceReceiver receiver, boolean restricted) { IFingerprintServiceReceiver receiver, boolean restricted, boolean internal) { IBiometricsFingerprint daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "startRemove: no fingerprint HAL!"); return; } if (internal) { Context context = getContext(); InternalRemovalClient client = new InternalRemovalClient(context, mHalDeviceId, token, receiver, fingerId, groupId, userId, restricted, context.getOpPackageName()) { @Override public void notifyUserActivity() { } @Override public IBiometricsFingerprint getFingerprintDaemon() { return FingerprintService.this.getFingerprintDaemon(); } }; startClient(client, true); } else { RemovalClient client = new RemovalClient(getContext(), mHalDeviceId, token, receiver, fingerId, groupId, userId, restricted, token.toString()) { @Override Loading @@ -468,14 +596,34 @@ public class FingerprintService extends SystemService implements IHwBinder.Death }; startClient(client, true); } } void startEnumerate(IBinder token, int userId, IFingerprintServiceReceiver receiver, boolean restricted) { IFingerprintServiceReceiver receiver, boolean restricted, boolean internal) { IBiometricsFingerprint daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "startEnumerate: no fingerprint HAL!"); return; } if (internal) { List<Fingerprint> enrolledList = getEnrolledFingerprints(userId); Context context = getContext(); InternalEnumerateClient client = new InternalEnumerateClient(context, mHalDeviceId, token, receiver, userId, userId, restricted, context.getOpPackageName(), enrolledList) { @Override public void notifyUserActivity() { } @Override public IBiometricsFingerprint getFingerprintDaemon() { return FingerprintService.this.getFingerprintDaemon(); } }; startClient(client, true); } else { EnumerateClient client = new EnumerateClient(getContext(), mHalDeviceId, token, receiver, userId, userId, restricted, token.toString()) { @Override Loading @@ -490,6 +638,7 @@ public class FingerprintService extends SystemService implements IHwBinder.Death }; startClient(client, true); } } public List<Fingerprint> getEnrolledFingerprints(int userId) { return mFingerprintUtils.getFingerprintsForUser(mContext, userId); Loading Loading @@ -978,11 +1127,13 @@ public class FingerprintService extends SystemService implements IHwBinder.Death mHandler.post(new Runnable() { @Override public void run() { startRemove(token, fingerId, groupId, userId, receiver, restricted); startRemove(token, fingerId, groupId, userId, receiver, restricted, false /* internal */); } }); } @Override // Binder call public void enumerate(final IBinder token, final int userId, final IFingerprintServiceReceiver receiver) { checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission Loading @@ -990,7 +1141,7 @@ public class FingerprintService extends SystemService implements IHwBinder.Death mHandler.post(new Runnable() { @Override public void run() { startEnumerate(token, userId, receiver, restricted); startEnumerate(token, userId, receiver, restricted, false /* internal */); } }); } Loading
services/core/java/com/android/server/fingerprint/InternalEnumerateClient.java 0 → 100644 +94 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 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.hardware.fingerprint.IFingerprintServiceReceiver; import android.os.IBinder; import android.util.Slog; import java.util.ArrayList; import java.util.List; /** * An internal class to help clean up unknown fingerprints in the hardware and software */ public abstract class InternalEnumerateClient extends EnumerateClient { private List<Fingerprint> mEnrolledList; private List<Fingerprint> mEnumeratedList = new ArrayList<>(); // list of fp to delete public InternalEnumerateClient(Context context, long halDeviceId, IBinder token, IFingerprintServiceReceiver receiver, int groupId, int userId, boolean restricted, String owner, List<Fingerprint> enrolledList) { super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner); mEnrolledList = enrolledList; } private void handleEnumeratedFingerprint(int fingerId, int groupId, int remaining) { boolean matched = false; for (int i=0; i<mEnrolledList.size(); i++) { if (mEnrolledList.get(i).getFingerId() == fingerId) { mEnrolledList.remove(i); matched = true; Slog.e(TAG, "Matched fingerprint fid=" + fingerId); break; } } // fingerId 0 means no fingerprints are in hardware if (!matched && fingerId != 0) { Fingerprint fingerprint = new Fingerprint("", groupId, fingerId, getHalDeviceId()); mEnumeratedList.add(fingerprint); } } private void doFingerprintCleanup() { if (mEnrolledList == null) { return; } for (Fingerprint f : mEnrolledList) { Slog.e(TAG, "Internal Enumerate: Removing dangling enrolled fingerprint: " + f.getName() + " " + f.getFingerId() + " " + f.getGroupId() + " " + f.getDeviceId()); FingerprintUtils.getInstance().removeFingerprintIdForUser(getContext(), f.getFingerId(), getTargetUserId()); } mEnrolledList.clear(); } public List<Fingerprint> getEnumeratedList() { return mEnumeratedList; } @Override public boolean onEnumerationResult(int fingerId, int groupId, int remaining) { handleEnumeratedFingerprint(fingerId, groupId, remaining); if (remaining == 0) { doFingerprintCleanup(); } return fingerId == 0; // done when id hits 0 } }
services/core/java/com/android/server/fingerprint/InternalRemovalClient.java 0 → 100644 +33 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 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.os.IBinder; import android.hardware.fingerprint.IFingerprintServiceReceiver; import com.android.server.fingerprint.RemovalClient; public abstract class InternalRemovalClient extends RemovalClient { public InternalRemovalClient(Context context, long halDeviceId, IBinder token, IFingerprintServiceReceiver receiver, int fingerId, int groupId, int userId, boolean restricted, String owner) { super(context, halDeviceId, token, receiver, fingerId, groupId, userId, restricted, owner); } }
services/core/java/com/android/server/fingerprint/RemovalClient.java +16 −5 Original line number Diff line number Diff line Loading @@ -59,12 +59,23 @@ public abstract class RemovalClient extends ClientMonitor { @Override public int stop(boolean initiatedByClient) { // We don't actually stop remove, but inform the client that the cancel operation succeeded // so we can start the next operation. if (initiatedByClient) { onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED, 0 /* vendorCode */); IBiometricsFingerprint daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "stopRemoval: no fingerprint HAL!"); return ERROR_ESRCH; } return 0; try { final int result = daemon.cancel(); if (result != 0) { Slog.w(TAG, "stopRemoval failed, result=" + result); return result; } if (DEBUG) Slog.w(TAG, "client " + getOwnerString() + " is no longer removing"); } catch (RemoteException e) { Slog.e(TAG, "stopRemoval failed", e); return ERROR_ESRCH; } return 0; // success } /* Loading