Remove redundant cancel events from FingerprintService

This fixes a bug where the framework was sending repeat cancel
events in response to terminal status (onAuthenticated(), onError())
which causes the underlying HAL implementation to get into a weird state.

Now, only client-initiated events like an explicit cancellation
or starting another authentication/enrollment invokes fingerprintd's
cancel() method.

Fixes bug 22438498

Change-Id: I762bab1c8635924848f9f4334db47a07130d5ae3
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index a71dfcd..8871e64 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -86,6 +86,7 @@
     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:
@@ -274,7 +275,7 @@
             Slog.w(TAG, "enroll: no fingeprintd!");
             return;
         }
-        stopPendingOperations();
+        stopPendingOperations(true);
         mEnrollClient = new ClientMonitor(token, receiver, groupId, restricted);
         final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
         try {
@@ -315,17 +316,23 @@
         return 0;
     }
 
-    private void stopPendingOperations() {
+    private void stopPendingOperations(boolean initiatedByClient) {
         if (mEnrollClient != null) {
-            stopEnrollment(mEnrollClient.token, true);
+            stopEnrollment(mEnrollClient.token, initiatedByClient);
         }
         if (mAuthClient != null) {
-            stopAuthentication(mAuthClient.token, true);
+            stopAuthentication(mAuthClient.token, initiatedByClient);
         }
         // mRemoveClient is allowed to continue
     }
 
-    void stopEnrollment(IBinder token, boolean notify) {
+    /**
+     * 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!");
@@ -333,15 +340,15 @@
         }
         final ClientMonitor client = mEnrollClient;
         if (client == null || client.token != token) return;
-        try {
-            int result = daemon.cancelEnrollment();
-            if (result != 0) {
-                Slog.w(TAG, "startEnrollCancel failed, result = " + result);
+        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);
             }
-        } catch (RemoteException e) {
-            Slog.e(TAG, "stopEnrollment failed", e);
-        }
-        if (notify) {
             client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
         }
         removeClient(mEnrollClient);
@@ -354,7 +361,7 @@
             Slog.w(TAG, "startAuthentication: no fingeprintd!");
             return;
         }
-        stopPendingOperations();
+        stopPendingOperations(true);
         mAuthClient = new ClientMonitor(token, receiver, groupId, restricted);
         if (inLockoutMode()) {
             Slog.v(TAG, "In lockout mode; disallowing authentication");
@@ -374,7 +381,13 @@
         }
     }
 
-    void stopAuthentication(IBinder token, boolean notify) {
+    /**
+     * 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!");
@@ -382,15 +395,15 @@
         }
         final ClientMonitor client = mAuthClient;
         if (client == null || client.token != token) return;
-        try {
-            int result = daemon.cancelAuthentication();
-            if (result != 0) {
-                Slog.w(TAG, "stopAuthentication failed, result=" + result);
+        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);
             }
-        } catch (RemoteException e) {
-            Slog.e(TAG, "stopAuthentication failed", e);
-        }
-        if (notify) {
             client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
         }
         removeClient(mAuthClient);
@@ -486,12 +499,14 @@
             receiver = null;
         }
 
+        @Override
         public void binderDied() {
             token = null;
             removeClient(this);
             receiver = null;
         }
 
+        @Override
         protected void finalize() throws Throwable {
             try {
                 if (token != null) {