Merge "Abort operation pruning only if it fails to make space." into mnc-dev
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index 85289ad..cb948fd 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -2507,7 +2507,16 @@
         while (err == KM_ERROR_TOO_MANY_OPERATIONS && mOperationMap.hasPruneableOperation()) {
             sp<IBinder> oldest = mOperationMap.getOldestPruneableOperation();
             ALOGD("Ran out of operation handles, trying to prune %p", oldest.get());
-            if (abort(oldest) != ::NO_ERROR) {
+
+            // We mostly ignore errors from abort() below because all we care about is whether at
+            // least one pruneable operation has been removed.
+            size_t op_count_before = mOperationMap.getPruneableOperationCount();
+            int abort_error = abort(oldest);
+            size_t op_count_after = mOperationMap.getPruneableOperationCount();
+            if (op_count_after >= op_count_before) {
+                // Failed to create space for a new operation. Bail to avoid an infinite loop.
+                ALOGE("Failed to remove pruneable operation %p, error: %d",
+                      oldest.get(), abort_error);
                 break;
             }
             err = dev->begin(dev, purpose, &key, &inParams, &outParams, &handle);
diff --git a/keystore/operation.cpp b/keystore/operation.cpp
index aa37101..4a71922 100644
--- a/keystore/operation.cpp
+++ b/keystore/operation.cpp
@@ -103,10 +103,14 @@
     }
 }
 
-bool OperationMap::hasPruneableOperation() {
+bool OperationMap::hasPruneableOperation() const {
     return mLru.size() != 0;
 }
 
+size_t OperationMap::getPruneableOperationCount() const {
+    return mLru.size();
+}
+
 sp<IBinder> OperationMap::getOldestPruneableOperation() {
     if (!hasPruneableOperation()) {
         return sp<IBinder>(NULL);
diff --git a/keystore/operation.h b/keystore/operation.h
index 6806388..01c4dbe 100644
--- a/keystore/operation.h
+++ b/keystore/operation.h
@@ -56,7 +56,8 @@
                       const keymaster1_device_t** outDev,
                       const keymaster_key_characteristics_t** outCharacteristics);
     bool removeOperation(sp<IBinder> token);
-    bool hasPruneableOperation();
+    bool hasPruneableOperation() const;
+    size_t getPruneableOperationCount() const;
     bool getOperationAuthToken(sp<IBinder> token, const hw_auth_token_t** outToken);
     bool setOperationAuthToken(sp<IBinder> token, const hw_auth_token_t* authToken);
     sp<IBinder> getOldestPruneableOperation();