Merge "finished implementation of fingerprintservice enumerate"
diff --git a/services/core/java/com/android/server/fingerprint/EnumerateClient.java b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
index 34f245f..1b8b89c 100644
--- a/services/core/java/com/android/server/fingerprint/EnumerateClient.java
+++ b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
@@ -58,7 +58,7 @@
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 {
@@ -102,12 +102,12 @@
@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.
}
}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 7d97ce4..b6e7932 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -85,6 +85,7 @@
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.
@@ -134,6 +135,20 @@
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<>();
@@ -257,10 +272,12 @@
// 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();
+ mEnumeratingUserIds.clear();
+ mUnknownFingerprints.clear();
for (UserInfo user : UserManager.get(mContext).getUsers(true /* excludeDying */)) {
int userId = getUserOrWorkProfileId(null, user.id);
+ mEnumeratingUserIds.add(userId);
if (!mAuthenticatorIds.containsKey(userId)) {
updateActiveGroup(userId, null);
}
@@ -270,12 +287,70 @@
if (t > 1000) {
Slog.w(TAG, "loadAuthenticatorIds() taking too long: " + t + "ms");
}
+
+ if (!mEnumeratingUserIds.isEmpty()) {
+ enumerateNextUser();
+ }
+ }
+
+ 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 */);
+ }
}
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 != null) {
+ 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) {
@@ -304,10 +379,18 @@
}
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();
+ }
}
protected void handleAuthenticated(long deviceId, int fingerId, int groupId,
@@ -434,7 +517,15 @@
ClientMonitor currentClient = mCurrentClient;
if (currentClient != null) {
if (DEBUG) Slog.v(TAG, "request stop current client " + currentClient.getOwnerString());
- currentClient.stop(initiatedByClient);
+ 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);
@@ -451,47 +542,86 @@
}
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;
}
- RemovalClient client = new RemovalClient(getContext(), mHalDeviceId, token,
- receiver, fingerId, groupId, userId, restricted, token.toString()) {
- @Override
- public void notifyUserActivity() {
- FingerprintService.this.userActivity();
- }
- @Override
- public IBiometricsFingerprint getFingerprintDaemon() {
- return FingerprintService.this.getFingerprintDaemon();
- }
- };
- startClient(client, true);
+ 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
+ public void notifyUserActivity() {
+ FingerprintService.this.userActivity();
+ }
+
+ @Override
+ public IBiometricsFingerprint getFingerprintDaemon() {
+ return FingerprintService.this.getFingerprintDaemon();
+ }
+ };
+ 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;
}
- EnumerateClient client = new EnumerateClient(getContext(), mHalDeviceId, token,
- receiver, userId, userId, restricted, token.toString()) {
- @Override
- public void notifyUserActivity() {
- FingerprintService.this.userActivity();
- }
+ 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);
+ }
+
+ @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
+ public void notifyUserActivity() {
+ FingerprintService.this.userActivity();
+ }
+
+ @Override
+ public IBiometricsFingerprint getFingerprintDaemon() {
+ return FingerprintService.this.getFingerprintDaemon();
+ }
+ };
+ startClient(client, true);
+ }
}
public List<Fingerprint> getEnrolledFingerprints(int userId) {
@@ -978,12 +1108,14 @@
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
@@ -991,7 +1123,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- startEnumerate(token, userId, receiver, restricted);
+ startEnumerate(token, userId, receiver, restricted, false /* internal */);
}
});
diff --git a/services/core/java/com/android/server/fingerprint/InternalEnumerateClient.java b/services/core/java/com/android/server/fingerprint/InternalEnumerateClient.java
new file mode 100644
index 0000000..f4d2596
--- /dev/null
+++ b/services/core/java/com/android/server/fingerprint/InternalEnumerateClient.java
@@ -0,0 +1,94 @@
+/*
+ * 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
+ }
+
+}
diff --git a/services/core/java/com/android/server/fingerprint/InternalRemovalClient.java b/services/core/java/com/android/server/fingerprint/InternalRemovalClient.java
new file mode 100644
index 0000000..19f61fe
--- /dev/null
+++ b/services/core/java/com/android/server/fingerprint/InternalRemovalClient.java
@@ -0,0 +1,33 @@
+/*
+ * 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);
+
+ }
+}