Multithreaded Keystore

This patch transitions keystore a threading model with one dispatcher
thread and one worker thread per keymaster instance, i.e. fallback, TEE,
Strongbox (if available). Singleton objects, such as the user state
database, the enforcement policy, and grant database have been moved to
KeyStore and were made concurrency safe.
Other noteworthy changes in this patch:

* Cached key characteristics. The key characteristics file used to hold
  a limited set of parameters used generate or import the key. This
  patch introduces a new blob type that holds full characteristics as
  returned by generate, import, or getKeyCharacteristics, with the
  original parameters mixed into the software enforced list. When
  keystore encounters a lagacy characteristics file it will grab the
  characteristics from keymaster, merge them with the cached parameters,
  and update the cache file to the new format. If keystore encounters
  the new cache no call to keymaster will be made for retrieving the
  key characteristics.
* Changed semantic of list. The list call takes a prefix used for
  filtering key entries. By the old semantic, list would return a list
  of aliases stripped of the given prefix. By the new semantic list
  always returns a filtered list of full alias string. Callers may
  strip prefixes if they are so inclined.
* Entertain per keymaster instance operation maps. With the introduction
  of Strongbox keystore had to deal with multiple keymaster instances.
  But until now it would entertain a single operations map. Keystore
  also enforces the invariant that no more than 15 operation slots are
  used so there is always a free slot available for vold. With a single
  operation map, this means no more than 15 slots can ever be used
  although with TEE and Strongbox there are a total of 32 slots. With
  strongbox implementation that have significantly fewer slots we see
  another effect of the single operation map. If a slot needs to be
  freed on Stronbox but the oldest operations are on TEE, the latter
  will be unnecessarily pruned before a Strongbox slot is freed up.
  With this patch each keymaster instance has its own operation map and
  pruning is performed on a per keymaster instance basis.
* Introduce KeyBlobEntries which are independent from files. To allow
  concurrent access to the key blob data base, entries can be
  individually locked so that operations on entries become atomic.
  LockedKeyBlobEntries are move only objects that track ownership of an
  Entry on the stack or in functor object representing keymaster worker
  requests. Entries must only be locked by the dispatcher Thread. Worker
  threads can only be granted access to a LockedKeyBlobEntry by the
  dispatcher thread. This allows the dispatcher thread to execute a
  barrier that waits until all locks held by workers have been
  relinquished to perform blob database maintenance operations, e.g.,
  clearing a uid of all entries.
* Verification tokens are now acquired asynchronously. When a begin
  operation requires a verification token a request is submitted to the
  other keymaster worker while the begin call returns. When the
  operation commences with update or finish, we block until the
  verification token becomes available.

As of this patch the keystore IPC interface is still synchronous. That
is, the dispatcher thread dispatches a request to a worker and then
waits until the worker has finished. In a followup patch the IPC
interface shall be made asynchronous so that multiple requests may be in
flight.

Test: Ran full CTS test suite
      atest android.keystore.cts
Bug: 111443219
Bug: 110495056
Change-Id: I305e28d784295a0095a34810d83202f7423498bd
diff --git a/keystore/Android.bp b/keystore/Android.bp
index 210b8b5..1168e90 100644
--- a/keystore/Android.bp
+++ b/keystore/Android.bp
@@ -13,6 +13,7 @@
     },
 
     clang: true,
+    cpp_std: "c++17",
 }
 
 cc_binary {
@@ -32,6 +33,7 @@
         "key_store_service.cpp",
         "keyblob_utils.cpp",
         "keymaster_enforcement.cpp",
+        "keymaster_worker.cpp",
         "keystore_attestation_id.cpp",
         "keystore_main.cpp",
         "keystore_utils.cpp",
diff --git a/keystore/KeyStore.cpp b/keystore/KeyStore.cpp
index 3a8861e..8c4844f 100644
--- a/keystore/KeyStore.cpp
+++ b/keystore/KeyStore.cpp
@@ -37,6 +37,8 @@
 #include "permissions.h"
 #include <keystore/keystore_hidl_support.h>
 
+#include "keymaster_worker.h"
+
 namespace keystore {
 
 const char* KeyStore::kOldMasterKey = ".masterkey";
@@ -47,35 +49,25 @@
 
 using android::String8;
 
-sp<Keymaster>& KeymasterDevices::operator[](SecurityLevel secLevel) {
-    static_assert(uint32_t(SecurityLevel::SOFTWARE) == 0 &&
-                      uint32_t(SecurityLevel::TRUSTED_ENVIRONMENT) == 1 &&
-                      uint32_t(SecurityLevel::STRONGBOX) == 2,
-                  "Numeric values of security levels have changed");
-    return at(static_cast<uint32_t>(secLevel));
-}
-
-sp<Keymaster> KeymasterDevices::operator[](SecurityLevel secLevel) const {
-    if (static_cast<uint32_t>(secLevel) > static_cast<uint32_t>(SecurityLevel::STRONGBOX)) {
-        LOG(ERROR) << "Invalid security level requested";
-        return nullptr;
-    }
-    return (*const_cast<KeymasterDevices*>(this))[secLevel];
-}
-
 KeyStore::KeyStore(Entropy* entropy, const KeymasterDevices& kmDevices,
                    SecurityLevel minimalAllowedSecurityLevelForNewKeys)
-    : mEntropy(entropy), mKmDevices(kmDevices),
-      mAllowNewFallback(minimalAllowedSecurityLevelForNewKeys == SecurityLevel::SOFTWARE) {
+    : mEntropy(entropy),
+      mAllowNewFallback(minimalAllowedSecurityLevelForNewKeys == SecurityLevel::SOFTWARE),
+      mConfirmationManager(new ConfirmationManager(this)) {
     memset(&mMetaData, '\0', sizeof(mMetaData));
+
+    static_assert(std::tuple_size<std::decay_t<decltype(kmDevices)>>::value ==
+                      std::tuple_size<decltype(mKmDevices)>::value,
+                  "KmasterDevices and KeymasterWorkers must have the same size");
+    for (size_t i = 0; i < kmDevices.size(); ++i) {
+        if (kmDevices[SecurityLevel(i)]) {
+            mKmDevices[SecurityLevel(i)] =
+                std::make_shared<KeymasterWorker>(kmDevices[SecurityLevel(i)], this);
+        }
+    }
 }
 
 KeyStore::~KeyStore() {
-    for (android::Vector<UserState*>::iterator it(mMasterKeys.begin()); it != mMasterKeys.end();
-         it++) {
-        delete *it;
-    }
-    mMasterKeys.clear();
 }
 
 ResponseCode KeyStore::initialize() {
@@ -88,134 +80,100 @@
 }
 
 ResponseCode KeyStore::initializeUser(const android::String8& pw, uid_t userId) {
-    UserState* userState = getUserState(userId);
+    auto userState = mUserStateDB.getUserState(userId);
     return userState->initialize(pw, mEntropy);
 }
 
 ResponseCode KeyStore::copyMasterKey(uid_t srcUser, uid_t dstUser) {
-    UserState* userState = getUserState(dstUser);
-    UserState* initState = getUserState(srcUser);
-    return userState->copyMasterKey(initState);
+    auto userState = mUserStateDB.getUserState(dstUser);
+    auto initState = mUserStateDB.getUserState(srcUser);
+    return userState->copyMasterKey(&initState);
 }
 
 ResponseCode KeyStore::writeMasterKey(const android::String8& pw, uid_t userId) {
-    UserState* userState = getUserState(userId);
+    auto userState = mUserStateDB.getUserState(userId);
     return userState->writeMasterKey(pw, mEntropy);
 }
 
 ResponseCode KeyStore::readMasterKey(const android::String8& pw, uid_t userId) {
-    UserState* userState = getUserState(userId);
+    auto userState = mUserStateDB.getUserState(userId);
     return userState->readMasterKey(pw, mEntropy);
 }
 
-/* Here is the encoding of keys. This is necessary in order to allow arbitrary
- * characters in keys. Characters in [0-~] are not encoded. Others are encoded
- * into two bytes. The first byte is one of [+-.] which represents the first
- * two bits of the character. The second byte encodes the rest of the bits into
- * [0-o]. Therefore in the worst case the length of a key gets doubled. Note
- * that Base64 cannot be used here due to the need of prefix match on keys. */
-
-static size_t encode_key_length(const android::String8& keyName) {
-    const uint8_t* in = reinterpret_cast<const uint8_t*>(keyName.string());
-    size_t length = keyName.length();
-    for (int i = length; i > 0; --i, ++in) {
-        if (*in < '0' || *in > '~') {
-            ++length;
-        }
-    }
-    return length;
+LockedKeyBlobEntry KeyStore::getLockedBlobEntryIfNotExists(const std::string& alias, uid_t uid) {
+    KeyBlobEntry kbe(alias, mUserStateDB.getUserStateByUid(uid)->getUserDirName(), uid);
+    auto result = LockedKeyBlobEntry::get(std::move(kbe));
+    if (result->hasKeyBlob()) return {};
+    return result;
 }
 
-static int encode_key(char* out, const android::String8& keyName) {
-    const uint8_t* in = reinterpret_cast<const uint8_t*>(keyName.string());
-    size_t length = keyName.length();
-    for (int i = length; i > 0; --i, ++in, ++out) {
-        if (*in < '0' || *in > '~') {
-            *out = '+' + (*in >> 6);
-            *++out = '0' + (*in & 0x3F);
-            ++length;
-        } else {
-            *out = *in;
-        }
-    }
-    *out = '\0';
-    return length;
-}
-
-android::String8 KeyStore::getKeyName(const android::String8& keyName, const BlobType type) {
-    std::vector<char> encoded(encode_key_length(keyName) + 1);  // add 1 for null char
-    encode_key(encoded.data(), keyName);
-    if (type == TYPE_KEY_CHARACTERISTICS) {
-        return android::String8::format(".chr_%s", encoded.data());
-    } else {
-        return android::String8(encoded.data());
-    }
-}
-
-android::String8 KeyStore::getKeyNameForUid(const android::String8& keyName, uid_t uid,
-                                            const BlobType type) {
-    std::vector<char> encoded(encode_key_length(keyName) + 1);  // add 1 for null char
-    encode_key(encoded.data(), keyName);
-    if (type == TYPE_KEY_CHARACTERISTICS) {
-        return android::String8::format(".%u_chr_%s", uid, encoded.data());
-    } else {
-        return android::String8::format("%u_%s", uid, encoded.data());
-    }
-}
-
-android::String8 KeyStore::getKeyNameForUidWithDir(const android::String8& keyName, uid_t uid,
-                                                   const BlobType type) {
-    std::vector<char> encoded(encode_key_length(keyName) + 1);  // add 1 for null char
-    encode_key(encoded.data(), keyName);
-
-    if (type == TYPE_KEY_CHARACTERISTICS) {
-        return android::String8::format("%s/.%u_chr_%s", getUserStateByUid(uid)->getUserDirName(),
-                                        uid, encoded.data());
-    } else {
-        return android::String8::format("%s/%u_%s", getUserStateByUid(uid)->getUserDirName(), uid,
-                                        encoded.data());
-    }
-}
-
-NullOr<android::String8> KeyStore::getBlobFileNameIfExists(const android::String8& alias, uid_t uid,
-                                                           const BlobType type) {
-    android::String8 filepath8(getKeyNameForUidWithDir(alias, uid, type));
-
-    if (!access(filepath8.string(), R_OK | W_OK)) return filepath8;
+std::optional<KeyBlobEntry> KeyStore::getBlobEntryIfExists(const std::string& alias, uid_t uid) {
+    KeyBlobEntry kbe(alias, mUserStateDB.getUserStateByUid(uid)->getUserDirName(), uid);
+    if (kbe.hasKeyBlob()) return kbe;
 
     // If this is one of the legacy UID->UID mappings, use it.
     uid_t euid = get_keystore_euid(uid);
     if (euid != uid) {
-        filepath8 = getKeyNameForUidWithDir(alias, euid, type);
-        if (!access(filepath8.string(), R_OK | W_OK)) return filepath8;
+        kbe = KeyBlobEntry(alias, mUserStateDB.getUserStateByUid(euid)->getUserDirName(), euid);
+        if (kbe.hasKeyBlob()) return kbe;
     }
 
     // They might be using a granted key.
-    auto grant = mGrants.get(uid, alias.string());
+    auto grant = mGrants.get(uid, alias);
     if (grant) {
-        filepath8 = String8::format(
-            "%s/%s", grant->owner_dir_name_.c_str(),
-            getKeyNameForUid(String8(grant->alias_.c_str()), grant->owner_uid_, type).c_str());
-        if (!access(filepath8.string(), R_OK | W_OK)) return filepath8;
+        kbe = grant->entry_;
+        if (kbe.hasKeyBlob()) return kbe;
     }
     return {};
 }
+LockedKeyBlobEntry KeyStore::getLockedBlobEntryIfExists(const std::string& alias, uid_t uid) {
+    auto blobentry = getBlobEntryIfExists(alias, uid);
+    if (!blobentry) return {};
+    LockedKeyBlobEntry lockedentry = LockedKeyBlobEntry::get(std::move(*blobentry));
+    if (!lockedentry || !lockedentry->hasKeyBlob()) return {};
+    return lockedentry;
+}
 
 void KeyStore::resetUser(uid_t userId, bool keepUnenryptedEntries) {
     android::String8 prefix("");
     android::Vector<android::String16> aliases;
-    UserState* userState = getUserState(userId);
-    if (list(prefix, &aliases, userId) != ResponseCode::NO_ERROR) {
+
+    // DO NOT
+    // move
+    // auto userState = userStateDB_.getUserState(userId);
+    // here, in an attempt to replace userStateDB_.getUserState(userId) with userState.
+    // userState is a proxy that holds a lock which may required by a worker.
+    // LockedKeyBlobEntry::list has a fence that waits until all workers have finished which may
+    // not happen if a user state lock is held. The following line only briefly grabs the lock.
+    // Grabbing the user state lock after the list call is also save since workers cannot grab
+    // blob entry locks.
+
+    auto userState = mUserStateDB.getUserState(userId);
+    std::string userDirName = userState->getUserDirName();
+    auto encryptionKey = userState->getEncryptionKey();
+    auto state = userState->getState();
+    // unlock the user state
+    userState = {};
+
+    ResponseCode rc;
+    std::list<LockedKeyBlobEntry> matches;
+
+    // must not be called by a keymaster worker. List waits for workers to relinquish all access
+    // to blob entries
+    std::tie(rc, matches) = LockedKeyBlobEntry::list(userDirName);
+    if (rc != ResponseCode::NO_ERROR) {
         return;
     }
-    for (uint32_t i = 0; i < aliases.size(); i++) {
-        android::String8 filename(aliases[i]);
-        filename = android::String8::format("%s/%s", userState->getUserDirName(),
-                                            getKeyName(filename, TYPE_ANY).string());
+
+    for (LockedKeyBlobEntry& lockedEntry : matches) {
         bool shouldDelete = true;
+
         if (keepUnenryptedEntries) {
             Blob blob;
-            ResponseCode rc = get(filename, &blob, ::TYPE_ANY, userId);
+            Blob charBlob;
+            ResponseCode rc;
+
+            std::tie(rc, blob, charBlob) = lockedEntry.readBlobs(encryptionKey, state);
 
             switch (rc) {
             case ResponseCode::SYSTEM_ERROR:
@@ -234,23 +192,18 @@
                 break;
 
             default:
-                ALOGE("Got unexpected return code %d from KeyStore::get()", rc);
+                ALOGE("Got unexpected return code %d from readBlobs", rc);
                 // This shouldn't happen.  To be on the safe side, delete it.
                 shouldDelete = true;
                 break;
             }
         }
         if (shouldDelete) {
-            del(filename, ::TYPE_ANY, userId);
-
-            // del() will fail silently if no cached characteristics are present for this alias.
-            android::String8 chr_filename(aliases[i]);
-            chr_filename = android::String8::format(
-                "%s/%s", userState->getUserDirName(),
-                getKeyName(chr_filename, TYPE_KEY_CHARACTERISTICS).string());
-            del(chr_filename, ::TYPE_KEY_CHARACTERISTICS, userId);
+            del(lockedEntry);
         }
     }
+
+    userState = mUserStateDB.getUserState(userId);
     if (!userState->deleteMasterKey()) {
         ALOGE("Failed to delete user %d's master key", userId);
     }
@@ -262,336 +215,138 @@
 }
 
 bool KeyStore::isEmpty(uid_t userId) const {
-    const UserState* userState = getUserState(userId);
-    if (userState == nullptr) {
-        return true;
-    }
-
-    DIR* dir = opendir(userState->getUserDirName());
-    if (!dir) {
-        return true;
-    }
-
-    bool result = true;
-    struct dirent* file;
-    while ((file = readdir(dir)) != nullptr) {
-        // We only care about files.
-        if (file->d_type != DT_REG) {
-            continue;
+    std::string userDirName;
+    {
+        // userState hold a lock which must be relinqhished before list is called. This scope
+        // prevents deadlocks.
+        auto userState = mUserStateDB.getUserState(userId);
+        if (!userState) {
+            return true;
         }
-
-        // Skip anything that starts with a "."
-        if (file->d_name[0] == '.') {
-            continue;
-        }
-
-        result = false;
-        break;
+        userDirName = userState->getUserDirName();
     }
-    closedir(dir);
-    return result;
+
+    ResponseCode rc;
+    std::list<LockedKeyBlobEntry> matches;
+
+    // must not be called by a keymaster worker. List waits for workers to relinquish all access
+    // to blob entries
+    std::tie(rc, matches) = LockedKeyBlobEntry::list(userDirName);
+
+    return rc == ResponseCode::SYSTEM_ERROR || matches.size() == 0;
 }
 
 void KeyStore::lock(uid_t userId) {
-    UserState* userState = getUserState(userId);
+    auto userState = mUserStateDB.getUserState(userId);
     userState->zeroizeMasterKeysInMemory();
     userState->setState(STATE_LOCKED);
 }
 
-static void maybeLogKeyIntegrityViolation(const char* filename, const BlobType type);
+static void maybeLogKeyIntegrityViolation(const LockedKeyBlobEntry& lockedEntry,
+                                          const BlobType type) {
+    if (!__android_log_security() || (type != TYPE_KEY_PAIR && type != TYPE_KEYMASTER_10)) return;
+    log_key_integrity_violation(lockedEntry->alias().c_str(), lockedEntry->uid());
+}
 
-ResponseCode KeyStore::get(const char* filename, Blob* keyBlob, const BlobType type, uid_t userId) {
-    UserState* userState = getUserState(userId);
-    ResponseCode rc;
+std::tuple<ResponseCode, Blob, Blob> KeyStore::get(const LockedKeyBlobEntry& blobfile) {
+    std::tuple<ResponseCode, Blob, Blob> result;
 
+    uid_t userId = get_user_id(blobfile->uid());
+    Blob& keyBlob = std::get<1>(result);
+    ResponseCode& rc = std::get<0>(result);
+
+    auto userState = mUserStateDB.getUserState(userId);
+    BlobType type = BlobType::TYPE_ANY;
     auto logOnScopeExit = android::base::make_scope_guard([&] {
         if (rc == ResponseCode::VALUE_CORRUPTED) {
-            maybeLogKeyIntegrityViolation(filename, type);
+            maybeLogKeyIntegrityViolation(blobfile, type);
         }
     });
 
-    rc = keyBlob->readBlob(filename, userState->getEncryptionKey(), userState->getState());
+    result = blobfile.readBlobs(userState->getEncryptionKey(), userState->getState());
     if (rc != ResponseCode::NO_ERROR) {
-        return rc;
+        return result;
     }
 
-    const uint8_t version = keyBlob->getVersion();
+    // update the type for logging (see scope_guard above)
+    type = keyBlob.getType();
+
+    const uint8_t version = keyBlob.getVersion();
     if (version < CURRENT_BLOB_VERSION) {
         /* If we upgrade the key, we need to write it to disk again. Then
          * it must be read it again since the blob is encrypted each time
          * it's written.
          */
-        if (upgradeBlob(filename, keyBlob, version, type, userId)) {
-            if ((rc = this->put(filename, keyBlob, userId)) != ResponseCode::NO_ERROR ||
-                (rc = keyBlob->readBlob(filename, userState->getEncryptionKey(),
-                                        userState->getState())) != ResponseCode::NO_ERROR) {
-                return rc;
+        if (upgradeBlob(&keyBlob, version)) {
+            if ((rc = this->put(blobfile, keyBlob, {})) != ResponseCode::NO_ERROR ||
+                (result = blobfile.readBlobs(userState->getEncryptionKey(), userState->getState()),
+                 rc) != ResponseCode::NO_ERROR) {
+                return result;
             }
         }
     }
 
-    /*
-     * This will upgrade software-backed keys to hardware-backed keys.
-     */
-    if (rc == ResponseCode::NO_ERROR && type == TYPE_KEY_PAIR && keyBlob->isFallback()) {
-        ResponseCode imported =
-            importKey(keyBlob->getValue(), keyBlob->getLength(), filename, userId,
-                      keyBlob->isEncrypted() ? KEYSTORE_FLAG_ENCRYPTED : KEYSTORE_FLAG_NONE);
-
-        // The HAL allowed the import, reget the key to have the "fresh" version.
-        if (imported == ResponseCode::NO_ERROR) {
-            rc = get(filename, keyBlob, TYPE_KEY_PAIR, userId);
-        }
-    }
-
-    // Keymaster 0.3 keys are valid keymaster 1.0 keys, so silently upgrade.
-    if (keyBlob->getType() == TYPE_KEY_PAIR) {
-        keyBlob->setType(TYPE_KEYMASTER_10);
-        rc = this->put(filename, keyBlob, userId);
-    }
-
-    if (type != TYPE_ANY && keyBlob->getType() != type) {
-        ALOGW("key found but type doesn't match: %d vs %d", keyBlob->getType(), type);
-        return ResponseCode::KEY_NOT_FOUND;
-    }
-
-    return rc;
+    return result;
 }
 
-ResponseCode KeyStore::put(const char* filename, Blob* keyBlob, uid_t userId) {
-    UserState* userState = getUserState(userId);
-    return keyBlob->writeBlob(filename, userState->getEncryptionKey(), userState->getState(),
-                              mEntropy);
+ResponseCode KeyStore::put(const LockedKeyBlobEntry& blobfile, Blob keyBlob,
+                           Blob characteristicsBlob) {
+    auto userState = mUserStateDB.getUserStateByUid(blobfile->uid());
+    return blobfile.writeBlobs(std::move(keyBlob), std::move(characteristicsBlob),
+                               userState->getEncryptionKey(), userState->getState(), mEntropy);
 }
 
-static NullOr<std::tuple<uid_t, std::string>> filename2UidAlias(const std::string& filename);
-
-ResponseCode KeyStore::del(const char* filename, const BlobType type, uid_t userId) {
+ResponseCode KeyStore::del(const LockedKeyBlobEntry& blobfile) {
     Blob keyBlob;
-    auto uidAlias = filename2UidAlias(filename);
-    uid_t uid;
-    std::string alias;
-    if (uidAlias.isOk()) {
-        std::tie(uid, alias) = std::move(uidAlias).value();
-    }
-    ResponseCode rc = get(filename, &keyBlob, type, userId);
-    if (rc == ResponseCode::VALUE_CORRUPTED) {
-        // The file is corrupt, the best we can do is rm it.
-        if (uidAlias.isOk()) {
-            // remove possible grants
-            mGrants.removeAllGrantsToKey(uid, alias);
-        }
-        return (unlink(filename) && errno != ENOENT) ? ResponseCode::SYSTEM_ERROR
-                                                     : ResponseCode::NO_ERROR;
-    }
+    Blob charactaristicsBlob;
+    ResponseCode rc;
+    uid_t uid = blobfile->uid();
+    std::string alias = blobfile->alias();
+
+    std::tie(rc, keyBlob, charactaristicsBlob) = get(blobfile);
+
+    // after getting the blob from the file system we scrub the filesystem.
+    mGrants.removeAllGrantsToKey(uid, alias);
+    auto result = blobfile.deleteBlobs();
+
     if (rc != ResponseCode::NO_ERROR) {
+        LOG(ERROR) << "get keyblob failed " << int(rc);
         return rc;
     }
 
+    // if we got the blob successfully, we try and delete it from the keymaster device
     auto dev = getDevice(keyBlob);
 
-    if (keyBlob.getType() == ::TYPE_KEY_PAIR || keyBlob.getType() == ::TYPE_KEYMASTER_10) {
-        auto ret = KS_HANDLE_HIDL_ERROR(dev->deleteKey(blob2hidlVec(keyBlob)));
-
-        // A device doesn't have to implement delete_key.
-        bool success = ret == ErrorCode::OK || ret == ErrorCode::UNIMPLEMENTED;
-        if (__android_log_security() && uidAlias.isOk()) {
-            android_log_event_list(SEC_TAG_KEY_DESTROYED)
-                << int32_t(success) << alias << int32_t(uid) << LOG_ID_SECURITY;
-        }
-        if (!success) return ResponseCode::SYSTEM_ERROR;
-    }
-
-    rc =
-        (unlink(filename) && errno != ENOENT) ? ResponseCode::SYSTEM_ERROR : ResponseCode::NO_ERROR;
-
-    if (rc == ResponseCode::NO_ERROR && keyBlob.getType() != ::TYPE_KEY_CHARACTERISTICS) {
-        // now that we have successfully deleted a key, let's make sure there are no stale grants
-        if (uidAlias.isOk()) {
-            mGrants.removeAllGrantsToKey(uid, alias);
-        }
-    }
-    return rc;
-}
-
-/*
- * Converts from the "escaped" format on disk to actual name.
- * This will be smaller than the input string.
- *
- * Characters that should combine with the next at the end will be truncated.
- */
-static size_t decode_key_length(const char* in, size_t length) {
-    size_t outLength = 0;
-
-    for (const char* end = in + length; in < end; in++) {
-        /* This combines with the next character. */
-        if (*in < '0' || *in > '~') {
-            continue;
-        }
-
-        outLength++;
-    }
-    return outLength;
-}
-
-static void decode_key(char* out, const char* in, size_t length) {
-    for (const char* end = in + length; in < end; in++) {
-        if (*in < '0' || *in > '~') {
-            /* Truncate combining characters at the end. */
-            if (in + 1 >= end) {
-                break;
+    if (keyBlob.getType() == ::TYPE_KEYMASTER_10) {
+        dev->deleteKey(blob2hidlVec(keyBlob), [alias, uid](Return<ErrorCode> rc) {
+            auto ret = KS_HANDLE_HIDL_ERROR(rc);
+            // A device doesn't have to implement delete_key.
+            bool success = ret == ErrorCode::OK || ret == ErrorCode::UNIMPLEMENTED;
+            if (__android_log_security()) {
+                android_log_event_list(SEC_TAG_KEY_DESTROYED)
+                    << int32_t(success) << alias << int32_t(uid) << LOG_ID_SECURITY;
             }
-
-            *out = (*in++ - '+') << 6;
-            *out++ |= (*in - '0') & 0x3F;
-        } else {
-            *out++ = *in;
-        }
-    }
-    *out = '\0';
-}
-
-static NullOr<std::tuple<uid_t, std::string>> filename2UidAlias(const std::string& filepath) {
-    auto filenamebase = filepath.find_last_of('/');
-    std::string filename =
-        filenamebase == std::string::npos ? filepath : filepath.substr(filenamebase + 1);
-
-    if (filename[0] == '.') return {};
-
-    auto sep = filename.find('_');
-    if (sep == std::string::npos) return {};
-
-    std::stringstream s(filename.substr(0, sep));
-    uid_t uid;
-    s >> uid;
-    if (!s) return {};
-
-    auto alias = filename.substr(sep + 1);
-
-    std::vector<char> alias_buffer(decode_key_length(alias.c_str(), alias.size()) + 1);
-
-    decode_key(alias_buffer.data(), alias.c_str(), alias.size());
-    return std::tuple<uid_t, std::string>(uid, alias_buffer.data());
-}
-
-ResponseCode KeyStore::list(const android::String8& prefix,
-                            android::Vector<android::String16>* matches, uid_t userId) {
-
-    UserState* userState = getUserState(userId);
-    size_t n = prefix.length();
-
-    DIR* dir = opendir(userState->getUserDirName());
-    if (!dir) {
-        ALOGW("can't open directory for user: %s", strerror(errno));
-        return ResponseCode::SYSTEM_ERROR;
-    }
-
-    struct dirent* file;
-    while ((file = readdir(dir)) != nullptr) {
-        // We only care about files.
-        if (file->d_type != DT_REG) {
-            continue;
-        }
-
-        // Skip anything that starts with a "."
-        if (file->d_name[0] == '.') {
-            continue;
-        }
-
-        if (!strncmp(prefix.string(), file->d_name, n)) {
-            const char* p = &file->d_name[n];
-            size_t plen = strlen(p);
-
-            size_t extra = decode_key_length(p, plen);
-            char* match = (char*)malloc(extra + 1);
-            if (match != nullptr) {
-                decode_key(match, p, plen);
-                matches->push(android::String16(match, extra));
-                free(match);
-            } else {
-                ALOGW("could not allocate match of size %zd", extra);
+            if (!success) {
+                LOG(ERROR) << "Keymaster delete for key " << alias << " of uid " << uid
+                           << " failed";
             }
-        }
+        });
     }
-    closedir(dir);
-    return ResponseCode::NO_ERROR;
+
+    return result;
 }
 
-std::string KeyStore::addGrant(const char* alias, uid_t granterUid, uid_t granteeUid) {
-    return mGrants.put(granteeUid, alias, getUserStateByUid(granterUid)->getUserDirName(),
-                       granterUid);
+std::string KeyStore::addGrant(const LockedKeyBlobEntry& blobfile, uid_t granteeUid) {
+    return mGrants.put(granteeUid, blobfile);
 }
 
-bool KeyStore::removeGrant(const char* alias, const uid_t granterUid, const uid_t granteeUid) {
-    return mGrants.removeByFileAlias(granteeUid, granterUid, alias);
+bool KeyStore::removeGrant(const LockedKeyBlobEntry& blobfile, const uid_t granteeUid) {
+    return mGrants.removeByFileAlias(granteeUid, blobfile);
 }
 void KeyStore::removeAllGrantsToUid(const uid_t granteeUid) {
     mGrants.removeAllGrantsToUid(granteeUid);
 }
 
-ResponseCode KeyStore::importKey(const uint8_t* key, size_t keyLen, const char* filename,
-                                 uid_t userId, int32_t flags) {
-    Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(nullptr, &key, keyLen));
-    if (!pkcs8.get()) {
-        return ResponseCode::SYSTEM_ERROR;
-    }
-    Unique_EVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get()));
-    if (!pkey.get()) {
-        return ResponseCode::SYSTEM_ERROR;
-    }
-    int type = EVP_PKEY_type(pkey->type);
-    AuthorizationSet params;
-    add_legacy_key_authorizations(type, &params);
-    switch (type) {
-    case EVP_PKEY_RSA:
-        params.push_back(TAG_ALGORITHM, Algorithm::RSA);
-        break;
-    case EVP_PKEY_EC:
-        params.push_back(TAG_ALGORITHM, Algorithm::EC);
-        break;
-    default:
-        ALOGW("Unsupported key type %d", type);
-        return ResponseCode::SYSTEM_ERROR;
-    }
-
-    AuthorizationSet opParams(params);
-    hidl_vec<uint8_t> blob;
-
-    ErrorCode error;
-    auto hidlCb = [&](ErrorCode ret, const hidl_vec<uint8_t>& keyBlob,
-                      const KeyCharacteristics& /* ignored */) {
-        error = ret;
-        if (error != ErrorCode::OK) return;
-        blob = keyBlob;
-    };
-    auto input = blob2hidlVec(key, keyLen);
-
-    SecurityLevel securityLevel = flagsToSecurityLevel(flags);
-    auto kmDevice = getDevice(securityLevel);
-    if (!kmDevice) {
-        // As of this writing the only caller is KeyStore::get in an attempt to import legacy
-        // software keys. It only ever requests TEE as target which must always be present.
-        // If we see this error, we probably have a new and unanticipated caller.
-        ALOGE("No implementation for security level %d. Cannot import key.", securityLevel);
-        return ResponseCode::SYSTEM_ERROR;
-    }
-
-    ErrorCode rc = KS_HANDLE_HIDL_ERROR(
-        kmDevice->importKey(params.hidl_data(), KeyFormat::PKCS8, input, hidlCb));
-    if (rc != ErrorCode::OK) return ResponseCode::SYSTEM_ERROR;
-    if (error != ErrorCode::OK) {
-        ALOGE("Keymaster error %d importing key pair", error);
-        return ResponseCode::SYSTEM_ERROR;
-    }
-
-    Blob keyBlob(&blob[0], blob.size(), nullptr, 0, TYPE_KEYMASTER_10);
-
-    keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
-    keyBlob.setSecurityLevel(securityLevel);
-
-    return put(filename, &keyBlob, userId);
-}
-
 bool KeyStore::isHardwareBacked(const android::String16& keyType) const {
     // if strongbox device is present TEE must also be present and of sufficiently high version
     // to support all keys in hardware
@@ -606,74 +361,34 @@
     return keyType == kEcKeyType && version.supportsEc;
 }
 
-ResponseCode KeyStore::getKeyForName(Blob* keyBlob, const android::String8& keyName,
-                                     const uid_t uid, const BlobType type) {
-    auto filepath8 = getBlobFileNameIfExists(keyName, uid, type);
-    uid_t userId = get_user_id(uid);
+std::tuple<ResponseCode, Blob, Blob, LockedKeyBlobEntry>
+KeyStore::getKeyForName(const android::String8& keyName, const uid_t uid, const BlobType type) {
+    std::tuple<ResponseCode, Blob, Blob, LockedKeyBlobEntry> result;
+    auto& [rc, keyBlob, charBlob, lockedEntry] = result;
 
-    if (filepath8.isOk()) return get(filepath8.value().string(), keyBlob, type, userId);
+    lockedEntry = getLockedBlobEntryIfExists(keyName.string(), uid);
 
-    return ResponseCode::KEY_NOT_FOUND;
-}
+    if (!lockedEntry) return rc = ResponseCode::KEY_NOT_FOUND, std::move(result);
 
-UserState* KeyStore::getUserState(uid_t userId) {
-    for (android::Vector<UserState*>::iterator it(mMasterKeys.begin()); it != mMasterKeys.end();
-         it++) {
-        UserState* state = *it;
-        if (state->getUserId() == userId) {
-            return state;
-        }
+    std::tie(rc, keyBlob, charBlob) = get(lockedEntry);
+
+    if (rc == ResponseCode::NO_ERROR) {
+        if (keyBlob.getType() != type) return rc = ResponseCode::KEY_NOT_FOUND, std::move(result);
     }
-
-    UserState* userState = new UserState(userId);
-    if (!userState->initialize()) {
-        /* There's not much we can do if initialization fails. Trying to
-         * unlock the keystore for that user will fail as well, so any
-         * subsequent request for this user will just return SYSTEM_ERROR.
-         */
-        ALOGE("User initialization failed for %u; subsuquent operations will fail", userId);
-    }
-    mMasterKeys.add(userState);
-    return userState;
+    return result;
 }
 
-UserState* KeyStore::getUserStateByUid(uid_t uid) {
-    uid_t userId = get_user_id(uid);
-    return getUserState(userId);
-}
-
-const UserState* KeyStore::getUserState(uid_t userId) const {
-    for (android::Vector<UserState*>::const_iterator it(mMasterKeys.begin());
-         it != mMasterKeys.end(); it++) {
-        UserState* state = *it;
-        if (state->getUserId() == userId) {
-            return state;
-        }
-    }
-
-    return nullptr;
-}
-
-const UserState* KeyStore::getUserStateByUid(uid_t uid) const {
-    uid_t userId = get_user_id(uid);
-    return getUserState(userId);
-}
-
-bool KeyStore::upgradeBlob(const char* filename, Blob* blob, const uint8_t oldVersion,
-                           const BlobType type, uid_t userId) {
+bool KeyStore::upgradeBlob(Blob* blob, const uint8_t oldVersion) {
     bool updated = false;
     uint8_t version = oldVersion;
 
+    if (!blob || !(*blob)) return false;
+
     /* From V0 -> V1: All old types were unknown */
     if (version == 0) {
-        ALOGV("upgrading to version 1 and setting type %d", type);
+        ALOGE("Failed to upgrade key blob. Ancient blob version 0 is no longer supported");
 
-        blob->setType(type);
-        if (type == TYPE_KEY_PAIR) {
-            importBlobAsKey(blob, filename, userId);
-        }
-        version = 1;
-        updated = true;
+        return false;
     }
 
     /* From V1 -> V2: All old keys were encrypted */
@@ -690,7 +405,6 @@
      * and write it.
      */
     if (updated) {
-        ALOGV("updated and writing file %s", filename);
         blob->setVersion(version);
     }
 
@@ -702,43 +416,6 @@
 };
 typedef std::unique_ptr<BIO, BIO_Delete> Unique_BIO;
 
-ResponseCode KeyStore::importBlobAsKey(Blob* blob, const char* filename, uid_t userId) {
-    // We won't even write to the blob directly with this BIO, so const_cast is okay.
-    Unique_BIO b(BIO_new_mem_buf(const_cast<uint8_t*>(blob->getValue()), blob->getLength()));
-    if (b.get() == nullptr) {
-        ALOGE("Problem instantiating BIO");
-        return ResponseCode::SYSTEM_ERROR;
-    }
-
-    Unique_EVP_PKEY pkey(PEM_read_bio_PrivateKey(b.get(), nullptr, nullptr, nullptr));
-    if (pkey.get() == nullptr) {
-        ALOGE("Couldn't read old PEM file");
-        return ResponseCode::SYSTEM_ERROR;
-    }
-
-    Unique_PKCS8_PRIV_KEY_INFO pkcs8(EVP_PKEY2PKCS8(pkey.get()));
-    int len = i2d_PKCS8_PRIV_KEY_INFO(pkcs8.get(), nullptr);
-    if (len < 0) {
-        ALOGE("Couldn't measure PKCS#8 length");
-        return ResponseCode::SYSTEM_ERROR;
-    }
-
-    std::unique_ptr<unsigned char[]> pkcs8key(new unsigned char[len]);
-    uint8_t* tmp = pkcs8key.get();
-    if (i2d_PKCS8_PRIV_KEY_INFO(pkcs8.get(), &tmp) != len) {
-        ALOGE("Couldn't convert to PKCS#8");
-        return ResponseCode::SYSTEM_ERROR;
-    }
-
-    ResponseCode rc = importKey(pkcs8key.get(), len, filename, userId,
-                                blob->isEncrypted() ? KEYSTORE_FLAG_ENCRYPTED : KEYSTORE_FLAG_NONE);
-    if (rc != ResponseCode::NO_ERROR) {
-        return rc;
-    }
-
-    return get(filename, blob, TYPE_KEY_PAIR, userId);
-}
-
 void KeyStore::readMetaData() {
     int in = TEMP_FAILURE_RETRY(open(kMetaDataFile, O_RDONLY));
     if (in < 0) {
@@ -772,14 +449,14 @@
     bool upgraded = false;
 
     if (mMetaData.version == 0) {
-        UserState* userState = getUserStateByUid(0);
+        auto userState = getUserStateDB().getUserStateByUid(0);
 
         // Initialize first so the directory is made.
         userState->initialize();
 
         // Migrate the old .masterkey file to user 0.
         if (access(kOldMasterKey, R_OK) == 0) {
-            if (rename(kOldMasterKey, userState->getMasterKeyFileName()) < 0) {
+            if (rename(kOldMasterKey, userState->getMasterKeyFileName().c_str()) < 0) {
                 ALOGE("couldn't migrate old masterkey: %s", strerror(errno));
                 return false;
             }
@@ -814,13 +491,13 @@
             if (end[0] != '_' || end[1] == 0) {
                 continue;
             }
-            UserState* otherUser = getUserStateByUid(thisUid);
+            auto otherUser = getUserStateDB().getUserStateByUid(thisUid);
             if (otherUser->getUserId() != 0) {
                 unlinkat(dirfd(dir), file->d_name, 0);
             }
 
             // Rename the file into user directory.
-            DIR* otherdir = opendir(otherUser->getUserDirName());
+            DIR* otherdir = opendir(otherUser->getUserDirName().c_str());
             if (otherdir == nullptr) {
                 ALOGW("couldn't open user directory for rename");
                 continue;
@@ -839,16 +516,11 @@
     return upgraded;
 }
 
-static void maybeLogKeyIntegrityViolation(const char* filename, const BlobType type) {
-    if (!__android_log_security() || (type != TYPE_KEY_PAIR && type != TYPE_KEYMASTER_10)) return;
-
-    auto uidAlias = filename2UidAlias(filename);
-    uid_t uid = -1;
-    std::string alias;
-
-    if (uidAlias.isOk()) std::tie(uid, alias) = std::move(uidAlias).value();
-
-    log_key_integrity_violation(alias.c_str(), uid);
+void KeyStore::binderDied(const ::android::wp<IBinder>& who) {
+    for (unsigned i = 0; i < mKmDevices.size(); ++i) {
+        if (mKmDevices[SecurityLevel(i)]) mKmDevices[SecurityLevel(i)]->binderDied(who);
+    }
+    getConfirmationManager().binderDied(who);
 }
 
 }  // namespace keystore
diff --git a/keystore/KeyStore.h b/keystore/KeyStore.h
index 23476d2..d2049a4 100644
--- a/keystore/KeyStore.h
+++ b/keystore/KeyStore.h
@@ -23,41 +23,67 @@
 
 #include <keystore/keymaster_types.h>
 
+#include "auth_token_table.h"
 #include "blob.h"
+#include "confirmation_manager.h"
 #include "grant_store.h"
+#include "keymaster_worker.h"
+#include "keystore_keymaster_enforcement.h"
+#include "operation.h"
 #include "user_state.h"
 
+#include <array>
+#include <optional>
+#include <tuple>
+
 namespace keystore {
 
 using ::android::sp;
 using keymaster::support::Keymaster;
 
-class KeymasterDevices : public std::array<sp<Keymaster>, 3> {
+template <typename T, size_t count> class Devices : public std::array<T, count> {
   public:
-    sp<Keymaster>& operator[](SecurityLevel secLevel);
-    sp<Keymaster> operator[](SecurityLevel secLevel) const;
+    T& operator[](SecurityLevel secLevel) {
+        static_assert(uint32_t(SecurityLevel::SOFTWARE) == 0 &&
+                          uint32_t(SecurityLevel::TRUSTED_ENVIRONMENT) == 1 &&
+                          uint32_t(SecurityLevel::STRONGBOX) == 2,
+                      "Numeric values of security levels have changed");
+        return std::array<T, count>::at(static_cast<uint32_t>(secLevel));
+    }
+    T operator[](SecurityLevel secLevel) const {
+        if (static_cast<uint32_t>(secLevel) > static_cast<uint32_t>(SecurityLevel::STRONGBOX)) {
+            LOG(ERROR) << "Invalid security level requested";
+            return {};
+        }
+        return (*const_cast<Devices*>(this))[secLevel];
+    }
 };
 
-class KeyStore {
+}  // namespace keystore
+
+namespace std {
+template <typename T, size_t count> class tuple_size<keystore::Devices<T, count>> {
+  public:
+    static constexpr size_t value = std::tuple_size<std::array<T, count>>::value;
+};
+}  // namespace std
+
+namespace keystore {
+
+using KeymasterWorkers = Devices<std::shared_ptr<KeymasterWorker>, 3>;
+using KeymasterDevices = Devices<sp<Keymaster>, 3>;
+
+class KeyStore : public ::android::IBinder::DeathRecipient {
   public:
     KeyStore(Entropy* entropy, const KeymasterDevices& kmDevices,
              SecurityLevel minimalAllowedSecurityLevelForNewKeys);
     ~KeyStore();
 
-    sp<Keymaster> getDevice(SecurityLevel securityLevel) const { return mKmDevices[securityLevel]; }
-
-    std::pair<sp<Keymaster>, SecurityLevel> getMostSecureDevice() const {
-        SecurityLevel level = SecurityLevel::STRONGBOX;
-        do {
-            if (mKmDevices[level].get()) {
-                return {mKmDevices[level], level};
-            }
-            level = static_cast<SecurityLevel>(static_cast<uint32_t>(level) - 1);
-        } while (level != SecurityLevel::SOFTWARE);
-        return {nullptr, SecurityLevel::SOFTWARE};
+    std::shared_ptr<KeymasterWorker> getDevice(SecurityLevel securityLevel) const {
+        return mKmDevices[securityLevel];
     }
 
-    sp<Keymaster> getFallbackDevice() const {
+    std::shared_ptr<KeymasterWorker> getFallbackDevice() const {
         // we only return the fallback device if the creation of new fallback key blobs is
         // allowed. (also see getDevice below)
         if (mAllowNewFallback) {
@@ -67,11 +93,13 @@
         }
     }
 
-    sp<Keymaster> getDevice(const Blob& blob) { return mKmDevices[blob.getSecurityLevel()]; }
+    std::shared_ptr<KeymasterWorker> getDevice(const Blob& blob) {
+        return mKmDevices[blob.getSecurityLevel()];
+    }
 
     ResponseCode initialize();
 
-    State getState(uid_t userId) { return getUserState(userId)->getState(); }
+    State getState(uid_t userId) { return mUserStateDB.getUserState(userId)->getState(); }
 
     ResponseCode initializeUser(const android::String8& pw, uid_t userId);
 
@@ -79,14 +107,9 @@
     ResponseCode writeMasterKey(const android::String8& pw, uid_t userId);
     ResponseCode readMasterKey(const android::String8& pw, uid_t userId);
 
-    android::String8 getKeyName(const android::String8& keyName, const BlobType type);
-    android::String8 getKeyNameForUid(const android::String8& keyName, uid_t uid,
-                                      const BlobType type);
-    android::String8 getKeyNameForUidWithDir(const android::String8& keyName, uid_t uid,
-                                             const BlobType type);
-    NullOr<android::String8> getBlobFileNameIfExists(const android::String8& alias, uid_t uid,
-                                                     const BlobType type);
-
+    LockedKeyBlobEntry getLockedBlobEntryIfNotExists(const std::string& alias, uid_t uid);
+    std::optional<KeyBlobEntry> getBlobEntryIfExists(const std::string& alias, uid_t uid);
+    LockedKeyBlobEntry getLockedBlobEntryIfExists(const std::string& alias, uid_t uid);
     /*
      * Delete entries owned by userId. If keepUnencryptedEntries is true
      * then only encrypted entries will be removed, otherwise all entries will
@@ -97,43 +120,28 @@
 
     void lock(uid_t userId);
 
-    ResponseCode get(const char* filename, Blob* keyBlob, const BlobType type, uid_t userId);
-    ResponseCode put(const char* filename, Blob* keyBlob, uid_t userId);
-    ResponseCode del(const char* filename, const BlobType type, uid_t userId);
-    ResponseCode list(const android::String8& prefix, android::Vector<android::String16>* matches,
-                      uid_t userId);
+    std::tuple<ResponseCode, Blob, Blob> get(const LockedKeyBlobEntry& blobfile);
+    ResponseCode put(const LockedKeyBlobEntry& blobfile, Blob keyBlob, Blob characteristicsBlob);
+    ResponseCode del(const LockedKeyBlobEntry& blobfile);
 
-    std::string addGrant(const char* alias, uid_t granterUid, uid_t granteeUid);
-    bool removeGrant(const char* alias, const uid_t granterUid, const uid_t granteeUid);
+    std::string addGrant(const LockedKeyBlobEntry& blobfile, uid_t granteeUid);
+    bool removeGrant(const LockedKeyBlobEntry& blobfile, const uid_t granteeUid);
     void removeAllGrantsToUid(const uid_t granteeUid);
 
-    ResponseCode importKey(const uint8_t* key, size_t keyLen, const char* filename, uid_t userId,
-                           int32_t flags);
+    ResponseCode importKey(const uint8_t* key, size_t keyLen, const LockedKeyBlobEntry& blobfile,
+                           uid_t userId, int32_t flags);
 
     bool isHardwareBacked(const android::String16& keyType) const;
 
-    ResponseCode getKeyForName(Blob* keyBlob, const android::String8& keyName, const uid_t uid,
-                               const BlobType type);
+    std::tuple<ResponseCode, Blob, Blob, LockedKeyBlobEntry>
+    getKeyForName(const android::String8& keyName, const uid_t uid, const BlobType type);
 
-    /**
-     * Returns any existing UserState or creates it if it doesn't exist.
-     */
-    UserState* getUserState(uid_t userId);
+    void binderDied(const ::android::wp<IBinder>& who) override;
 
-    /**
-     * Returns any existing UserState or creates it if it doesn't exist.
-     */
-    UserState* getUserStateByUid(uid_t uid);
-
-    /**
-     * Returns NULL if the UserState doesn't already exist.
-     */
-    const UserState* getUserState(uid_t userId) const;
-
-    /**
-     * Returns NULL if the UserState doesn't already exist.
-     */
-    const UserState* getUserStateByUid(uid_t uid) const;
+    UserStateDB& getUserStateDB() { return mUserStateDB; }
+    AuthTokenTable& getAuthTokenTable() { return mAuthTokenTable; }
+    KeystoreKeymasterEnforcement& getEnforcementPolicy() { return mEnforcementPolicy; }
+    ConfirmationManager& getConfirmationManager() { return *mConfirmationManager; }
 
   private:
     static const char* kOldMasterKey;
@@ -142,10 +150,14 @@
     static const android::String16 kEcKeyType;
     Entropy* mEntropy;
 
-    KeymasterDevices mKmDevices;
+    KeymasterWorkers mKmDevices;
+
     bool mAllowNewFallback;
 
-    android::Vector<UserState*> mMasterKeys;
+    UserStateDB mUserStateDB;
+    AuthTokenTable mAuthTokenTable;
+    KeystoreKeymasterEnforcement mEnforcementPolicy;
+    sp<ConfirmationManager> mConfirmationManager;
 
     ::keystore::GrantStore mGrants;
 
@@ -156,15 +168,7 @@
     /**
      * Upgrade the key from the current version to whatever is newest.
      */
-    bool upgradeBlob(const char* filename, Blob* blob, const uint8_t oldVersion,
-                     const BlobType type, uid_t uid);
-
-    /**
-     * Takes a blob that is an PEM-encoded RSA key as a byte array and converts it to a DER-encoded
-     * PKCS#8 for import into a keymaster.  Then it overwrites the original blob with the new blob
-     * format that is returned from the keymaster.
-     */
-    ResponseCode importBlobAsKey(Blob* blob, const char* filename, uid_t uid);
+    bool upgradeBlob(Blob* blob, const uint8_t oldVersion);
 
     void readMetaData();
     void writeMetaData();
diff --git a/keystore/KeymasterArguments.cpp b/keystore/KeymasterArguments.cpp
index 829156c..60b86cc 100644
--- a/keystore/KeymasterArguments.cpp
+++ b/keystore/KeymasterArguments.cpp
@@ -34,6 +34,9 @@
     return keystore::writeParamSetToParcel(data_, out);
 };
 
+KeymasterArguments::KeymasterArguments(hardware::hidl_vec<keystore::KeyParameter>&& other)
+    : data_(std::move(other)) {}
+
 KeymasterArguments::KeymasterArguments(const hardware::hidl_vec<keystore::KeyParameter>& other)
     : data_(other) {}
 
diff --git a/keystore/OperationResult.cpp b/keystore/OperationResult.cpp
index 53c8d62..f4d2cc6 100644
--- a/keystore/OperationResult.cpp
+++ b/keystore/OperationResult.cpp
@@ -55,6 +55,12 @@
     return OK;
 }
 
+OperationResult operationFailed(const ::keystore::KeyStoreServiceReturnCode& error) {
+    OperationResult opResult = {};
+    opResult.resultCode = error;
+    return opResult;
+}
+
 }  // namespace keymaster
 }  // namespace security
 }  // namespace android
diff --git a/keystore/auth_token_table.cpp b/keystore/auth_token_table.cpp
index 63282e6..6bffa7c 100644
--- a/keystore/auth_token_table.cpp
+++ b/keystore/auth_token_table.cpp
@@ -84,6 +84,7 @@
           static_cast<unsigned long long>(new_entry.token().timestamp),
           static_cast<long long>(new_entry.time_received()));
 
+    std::lock_guard<std::mutex> lock(entries_mutex_);
     RemoveEntriesSupersededBy(new_entry);
     if (entries_.size() >= max_entries_) {
         ALOGW("Auth token table filled up; replacing oldest entry");
@@ -110,10 +111,13 @@
     return is_secret_key_operation(algorithm, purpose) && key_info.find(Tag::AUTH_TIMEOUT) == -1;
 }
 
-AuthTokenTable::Error AuthTokenTable::FindAuthorization(const AuthorizationSet& key_info,
-                                                        KeyPurpose purpose, uint64_t op_handle,
-                                                        const HardwareAuthToken** found) {
-    if (!KeyRequiresAuthentication(key_info, purpose)) return AUTH_NOT_REQUIRED;
+std::tuple<AuthTokenTable::Error, HardwareAuthToken>
+AuthTokenTable::FindAuthorization(const AuthorizationSet& key_info, KeyPurpose purpose,
+                                  uint64_t op_handle) {
+
+    std::lock_guard<std::mutex> lock(entries_mutex_);
+
+    if (!KeyRequiresAuthentication(key_info, purpose)) return {AUTH_NOT_REQUIRED, {}};
 
     auto auth_type =
         defaultOr(key_info.GetTagValue(TAG_USER_AUTH_TYPE), HardwareAuthenticatorType::NONE);
@@ -122,55 +126,51 @@
     ExtractSids(key_info, &key_sids);
 
     if (KeyRequiresAuthPerOperation(key_info, purpose))
-        return FindAuthPerOpAuthorization(key_sids, auth_type, op_handle, found);
+        return FindAuthPerOpAuthorization(key_sids, auth_type, op_handle);
     else
-        return FindTimedAuthorization(key_sids, auth_type, key_info, found);
+        return FindTimedAuthorization(key_sids, auth_type, key_info);
 }
 
-AuthTokenTable::Error
-AuthTokenTable::FindAuthPerOpAuthorization(const std::vector<uint64_t>& sids,
-                                           HardwareAuthenticatorType auth_type, uint64_t op_handle,
-                                           const HardwareAuthToken** found) {
-    if (op_handle == 0) return OP_HANDLE_REQUIRED;
+std::tuple<AuthTokenTable::Error, HardwareAuthToken> AuthTokenTable::FindAuthPerOpAuthorization(
+    const std::vector<uint64_t>& sids, HardwareAuthenticatorType auth_type, uint64_t op_handle) {
+    if (op_handle == 0) return {OP_HANDLE_REQUIRED, {}};
 
     auto matching_op = find_if(
         entries_, [&](Entry& e) { return e.token().challenge == op_handle && !e.completed(); });
 
-    if (matching_op == entries_.end()) return AUTH_TOKEN_NOT_FOUND;
+    if (matching_op == entries_.end()) return {AUTH_TOKEN_NOT_FOUND, {}};
 
-    if (!matching_op->SatisfiesAuth(sids, auth_type)) return AUTH_TOKEN_WRONG_SID;
+    if (!matching_op->SatisfiesAuth(sids, auth_type)) return {AUTH_TOKEN_WRONG_SID, {}};
 
-    *found = &matching_op->token();
-    return OK;
+    return {OK, matching_op->token()};
 }
 
-AuthTokenTable::Error AuthTokenTable::FindTimedAuthorization(const std::vector<uint64_t>& sids,
-                                                             HardwareAuthenticatorType auth_type,
-                                                             const AuthorizationSet& key_info,
-                                                             const HardwareAuthToken** found) {
+std::tuple<AuthTokenTable::Error, HardwareAuthToken>
+AuthTokenTable::FindTimedAuthorization(const std::vector<uint64_t>& sids,
+                                       HardwareAuthenticatorType auth_type,
+                                       const AuthorizationSet& key_info) {
     Entry* newest_match = nullptr;
     for (auto& entry : entries_)
         if (entry.SatisfiesAuth(sids, auth_type) && entry.is_newer_than(newest_match))
             newest_match = &entry;
 
-    if (!newest_match) return AUTH_TOKEN_NOT_FOUND;
+    if (!newest_match) return {AUTH_TOKEN_NOT_FOUND, {}};
 
     auto timeout = defaultOr(key_info.GetTagValue(TAG_AUTH_TIMEOUT), 0);
 
     time_t now = clock_function_();
     if (static_cast<int64_t>(newest_match->time_received()) + timeout < static_cast<int64_t>(now))
-        return AUTH_TOKEN_EXPIRED;
+        return {AUTH_TOKEN_EXPIRED, {}};
 
     if (key_info.GetTagValue(TAG_ALLOW_WHILE_ON_BODY).isOk()) {
         if (static_cast<int64_t>(newest_match->time_received()) <
             static_cast<int64_t>(last_off_body_)) {
-            return AUTH_TOKEN_EXPIRED;
+            return {AUTH_TOKEN_EXPIRED, {}};
         }
     }
 
     newest_match->UpdateLastUse(now);
-    *found = &newest_match->token();
-    return OK;
+    return {OK, newest_match->token()};
 }
 
 void AuthTokenTable::ExtractSids(const AuthorizationSet& key_info, std::vector<uint64_t>* sids) {
@@ -190,15 +190,24 @@
 }
 
 void AuthTokenTable::Clear() {
+    std::lock_guard<std::mutex> lock(entries_mutex_);
+
     entries_.clear();
 }
 
+size_t AuthTokenTable::size() const {
+    std::lock_guard<std::mutex> lock(entries_mutex_);
+    return entries_.size();
+}
+
 bool AuthTokenTable::IsSupersededBySomeEntry(const Entry& entry) {
     return std::any_of(entries_.begin(), entries_.end(),
                        [&](Entry& e) { return e.Supersedes(entry); });
 }
 
 void AuthTokenTable::MarkCompleted(const uint64_t op_handle) {
+    std::lock_guard<std::mutex> lock(entries_mutex_);
+
     auto found = find_if(entries_, [&](Entry& e) { return e.token().challenge == op_handle; });
     if (found == entries_.end()) return;
 
diff --git a/keystore/auth_token_table.h b/keystore/auth_token_table.h
index 4110370..7b48a6c 100644
--- a/keystore/auth_token_table.h
+++ b/keystore/auth_token_table.h
@@ -15,6 +15,7 @@
  */
 
 #include <memory>
+#include <mutex>
 #include <vector>
 
 #include <keystore/keymaster_types.h>
@@ -72,8 +73,8 @@
      *
      * The table retains ownership of the returned object.
      */
-    Error FindAuthorization(const AuthorizationSet& key_info, KeyPurpose purpose,
-                            uint64_t op_handle, const HardwareAuthToken** found);
+    std::tuple<Error, HardwareAuthToken> FindAuthorization(const AuthorizationSet& key_info,
+                                                           KeyPurpose purpose, uint64_t op_handle);
 
     /**
      * Mark operation completed.  This allows tokens associated with the specified operation to be
@@ -89,7 +90,13 @@
 
     void Clear();
 
-    size_t size() { return entries_.size(); }
+    /**
+     * This function shall only be used for testing.
+     *
+     * BEWARE: Since the auth token table can be accessed
+     * concurrently, the size may be out dated as soon as it returns.
+     */
+    size_t size() const;
 
   private:
     friend class AuthTokenTableTest;
@@ -142,16 +149,21 @@
         bool operation_completed_;
     };
 
-    Error FindAuthPerOpAuthorization(const std::vector<uint64_t>& sids,
-                                     HardwareAuthenticatorType auth_type, uint64_t op_handle,
-                                     const HardwareAuthToken** found);
-    Error FindTimedAuthorization(const std::vector<uint64_t>& sids,
-                                 HardwareAuthenticatorType auth_type,
-                                 const AuthorizationSet& key_info, const HardwareAuthToken** found);
+    std::tuple<Error, HardwareAuthToken>
+    FindAuthPerOpAuthorization(const std::vector<uint64_t>& sids,
+                               HardwareAuthenticatorType auth_type, uint64_t op_handle);
+    std::tuple<Error, HardwareAuthToken> FindTimedAuthorization(const std::vector<uint64_t>& sids,
+                                                                HardwareAuthenticatorType auth_type,
+                                                                const AuthorizationSet& key_info);
     void ExtractSids(const AuthorizationSet& key_info, std::vector<uint64_t>* sids);
     void RemoveEntriesSupersededBy(const Entry& entry);
     bool IsSupersededBySomeEntry(const Entry& entry);
 
+    /**
+     * Guards the entries_ vector against concurrent modification. All public facing methods
+     * reading of modifying the vector must grab this mutex.
+     */
+    mutable std::mutex entries_mutex_;
     std::vector<Entry> entries_;
     size_t max_entries_;
     time_t last_off_body_;
diff --git a/keystore/authorization_set.cpp b/keystore/authorization_set.cpp
deleted file mode 100644
index 537fe3d..0000000
--- a/keystore/authorization_set.cpp
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * 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.
- */
-
-#include <keystore/keymaster_types.h>
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits>
-#include <ostream>
-#include <istream>
-
-#include <new>
-
-namespace keystore {
-
-inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
-    if (a.tag != b.tag) return a.tag < b.tag;
-    int retval;
-    switch (typeFromTag(a.tag)) {
-    case TagType::INVALID:
-    case TagType::BOOL:
-        return false;
-    case TagType::ENUM:
-    case TagType::ENUM_REP:
-    case TagType::UINT:
-    case TagType::UINT_REP:
-        return a.f.integer < b.f.integer;
-    case TagType::ULONG:
-    case TagType::ULONG_REP:
-        return a.f.longInteger < b.f.longInteger;
-    case TagType::DATE:
-        return a.f.dateTime < b.f.dateTime;
-    case TagType::BIGNUM:
-    case TagType::BYTES:
-        // Handle the empty cases.
-        if (a.blob.size() == 0)
-            return b.blob.size() != 0;
-        if (b.blob.size() == 0) return false;
-
-        retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size()));
-        // if one is the prefix of the other the longer wins
-        if (retval == 0) return a.blob.size() < b.blob.size();
-        // Otherwise a is less if a is less.
-        else return retval < 0;
-    }
-    return false;
-}
-
-inline bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) {
-    if (a.tag != b.tag) return false;
-
-    switch (typeFromTag(a.tag)) {
-    case TagType::INVALID:
-    case TagType::BOOL:
-        return true;
-    case TagType::ENUM:
-    case TagType::ENUM_REP:
-    case TagType::UINT:
-    case TagType::UINT_REP:
-        return a.f.integer == b.f.integer;
-    case TagType::ULONG:
-    case TagType::ULONG_REP:
-        return a.f.longInteger == b.f.longInteger;
-    case TagType::DATE:
-        return a.f.dateTime == b.f.dateTime;
-    case TagType::BIGNUM:
-    case TagType::BYTES:
-        if (a.blob.size() != b.blob.size()) return false;
-        return a.blob.size() == 0 ||
-                memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0;
-    }
-    return false;
-}
-
-void AuthorizationSet::Sort() {
-    std::sort(data_.begin(), data_.end(), keyParamLess);
-}
-
-void AuthorizationSet::Deduplicate() {
-    if (data_.empty()) return;
-
-    Sort();
-    std::vector<KeyParameter> result;
-
-    auto curr = data_.begin();
-    auto prev = curr++;
-    for (; curr != data_.end(); ++prev, ++curr) {
-        if (prev->tag == Tag::INVALID) continue;
-
-        if (!keyParamEqual(*prev, *curr)) {
-            result.emplace_back(std::move(*prev));
-        }
-    }
-    result.emplace_back(std::move(*prev));
-
-    std::swap(data_, result);
-}
-
-void AuthorizationSet::Union(const AuthorizationSet& other) {
-    data_.insert(data_.end(), other.data_.begin(), other.data_.end());
-    Deduplicate();
-}
-
-void AuthorizationSet::Subtract(const AuthorizationSet& other) {
-    Deduplicate();
-
-    auto i = other.begin();
-    while (i != other.end()) {
-        int pos = -1;
-        do {
-            pos = find(i->tag, pos);
-            if (pos != -1 && keyParamEqual(*i, data_[pos])) {
-                data_.erase(data_.begin() + pos);
-                break;
-            }
-        } while (pos != -1);
-        ++i;
-    }
-}
-
-int AuthorizationSet::find(Tag tag, int begin) const {
-    auto iter = data_.begin() + (1 + begin);
-
-    while (iter != data_.end() && iter->tag != tag) ++iter;
-
-    if (iter != data_.end()) return iter - data_.begin();
-    return -1;
-}
-
-bool AuthorizationSet::erase(int index) {
-    auto pos = data_.begin() + index;
-    if (pos != data_.end()) {
-        data_.erase(pos);
-        return true;
-    }
-    return false;
-}
-
-KeyParameter& AuthorizationSet::operator[](int at) {
-    return data_[at];
-}
-
-const KeyParameter& AuthorizationSet::operator[](int at) const {
-    return data_[at];
-}
-
-void AuthorizationSet::Clear() {
-    data_.clear();
-}
-
-size_t AuthorizationSet::GetTagCount(Tag tag) const {
-    size_t count = 0;
-    for (int pos = -1; (pos = find(tag, pos)) != -1;)
-        ++count;
-    return count;
-}
-
-NullOr<const KeyParameter&> AuthorizationSet::GetEntry(Tag tag) const {
-    int pos = find(tag);
-    if (pos == -1) return {};
-    return data_[pos];
-}
-
-/**
- * Persistent format is:
- * | 32 bit indirect_size         |
- * --------------------------------
- * | indirect_size bytes of data  | this is where the blob data is stored
- * --------------------------------
- * | 32 bit element_count         | number of entries
- * | 32 bit elements_size         | total bytes used by entries (entries have variable length)
- * --------------------------------
- * | elementes_size bytes of data | where the elements are stored
- */
-
-/**
- * Persistent format of blobs and bignums:
- * | 32 bit tag             |
- * | 32 bit blob_length     |
- * | 32 bit indirect_offset |
- */
-
-struct OutStreams {
-    std::ostream& indirect;
-    std::ostream& elements;
-};
-
-OutStreams& serializeParamValue(OutStreams& out, const hidl_vec<uint8_t>& blob) {
-    uint32_t buffer;
-
-    // write blob_length
-    auto blob_length = blob.size();
-    if (blob_length > std::numeric_limits<uint32_t>::max()) {
-        out.elements.setstate(std::ios_base::badbit);
-        return out;
-    }
-    buffer = blob_length;
-    out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
-
-    // write indirect_offset
-    auto offset = out.indirect.tellp();
-    if (offset < 0 || offset > std::numeric_limits<uint32_t>::max() ||
-            uint32_t(offset) + uint32_t(blob_length) < uint32_t(offset)) { // overflow check
-        out.elements.setstate(std::ios_base::badbit);
-        return out;
-    }
-    buffer = offset;
-    out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
-
-    // write blob to indirect stream
-    if(blob_length)
-        out.indirect.write(reinterpret_cast<const char*>(&blob[0]), blob_length);
-
-    return out;
-}
-
-template <typename T>
-OutStreams& serializeParamValue(OutStreams& out, const T& value) {
-    out.elements.write(reinterpret_cast<const char*>(&value), sizeof(T));
-    return out;
-}
-
-OutStreams& serialize(TAG_INVALID_t&&, OutStreams& out, const KeyParameter&) {
-    // skip invalid entries.
-    return out;
-}
-template <typename T>
-OutStreams& serialize(T ttag, OutStreams& out, const KeyParameter& param) {
-    out.elements.write(reinterpret_cast<const char*>(&param.tag), sizeof(int32_t));
-    return serializeParamValue(out, accessTagValue(ttag, param));
-}
-
-template <typename... T>
-struct choose_serializer;
-template <typename... Tags>
-struct choose_serializer<MetaList<Tags...>> {
-    static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
-        return choose_serializer<Tags...>::serialize(out, param);
-    }
-};
-template <>
-struct choose_serializer<> {
-    static OutStreams& serialize(OutStreams& out, const KeyParameter&) {
-        return out;
-    }
-};
-template <TagType tag_type, Tag tag, typename... Tail>
-struct choose_serializer<TypedTag<tag_type, tag>, Tail...> {
-    static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
-        if (param.tag == tag) {
-            return keystore::serialize(TypedTag<tag_type, tag>(), out, param);
-        } else {
-            return choose_serializer<Tail...>::serialize(out, param);
-        }
-    }
-};
-
-OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
-    return choose_serializer<all_tags_t>::serialize(out, param);
-}
-
-std::ostream& serialize(std::ostream& out, const std::vector<KeyParameter>& params) {
-    std::stringstream indirect;
-    std::stringstream elements;
-    OutStreams streams = { indirect, elements };
-    for (const auto& param: params) {
-        serialize(streams, param);
-    }
-    if (indirect.bad() || elements.bad()) {
-        out.setstate(std::ios_base::badbit);
-        return out;
-    }
-    auto pos = indirect.tellp();
-    if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
-        out.setstate(std::ios_base::badbit);
-        return out;
-    }
-    uint32_t indirect_size = pos;
-    pos = elements.tellp();
-    if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
-        out.setstate(std::ios_base::badbit);
-        return out;
-    }
-    uint32_t elements_size = pos;
-    uint32_t element_count = params.size();
-
-    out.write(reinterpret_cast<const char*>(&indirect_size), sizeof(uint32_t));
-
-    pos = out.tellp();
-    if (indirect_size)
-        out << indirect.rdbuf();
-    assert(out.tellp() - pos == indirect_size);
-
-    out.write(reinterpret_cast<const char*>(&element_count), sizeof(uint32_t));
-    out.write(reinterpret_cast<const char*>(&elements_size), sizeof(uint32_t));
-
-    pos = out.tellp();
-    if (elements_size)
-        out << elements.rdbuf();
-    assert(out.tellp() - pos == elements_size);
-
-    return out;
-}
-
-struct InStreams {
-    std::istream& indirect;
-    std::istream& elements;
-};
-
-InStreams& deserializeParamValue(InStreams& in, hidl_vec<uint8_t>* blob) {
-    uint32_t blob_length = 0;
-    uint32_t offset = 0;
-    in.elements.read(reinterpret_cast<char*>(&blob_length), sizeof(uint32_t));
-    blob->resize(blob_length);
-    in.elements.read(reinterpret_cast<char*>(&offset), sizeof(uint32_t));
-    in.indirect.seekg(offset);
-    in.indirect.read(reinterpret_cast<char*>(&(*blob)[0]), blob->size());
-    return in;
-}
-
-template <typename T>
-InStreams& deserializeParamValue(InStreams& in, T* value) {
-    in.elements.read(reinterpret_cast<char*>(value), sizeof(T));
-    return in;
-}
-
-InStreams& deserialize(TAG_INVALID_t&&, InStreams& in, KeyParameter*) {
-    // there should be no invalid KeyParamaters but if handle them as zero sized.
-    return in;
-}
-
-template <typename T>
-InStreams& deserialize(T&& ttag, InStreams& in, KeyParameter* param) {
-    return deserializeParamValue(in, &accessTagValue(ttag, *param));
-}
-
-template <typename... T>
-struct choose_deserializer;
-template <typename... Tags>
-struct choose_deserializer<MetaList<Tags...>> {
-    static InStreams& deserialize(InStreams& in, KeyParameter* param) {
-        return choose_deserializer<Tags...>::deserialize(in, param);
-    }
-};
-template <>
-struct choose_deserializer<> {
-    static InStreams& deserialize(InStreams& in, KeyParameter*) {
-        // encountered an unknown tag -> fail parsing
-        in.elements.setstate(std::ios_base::badbit);
-        return in;
-    }
-};
-template <TagType tag_type, Tag tag, typename... Tail>
-struct choose_deserializer<TypedTag<tag_type, tag>, Tail...> {
-    static InStreams& deserialize(InStreams& in, KeyParameter* param) {
-        if (param->tag == tag) {
-            return keystore::deserialize(TypedTag<tag_type, tag>(), in, param);
-        } else {
-            return choose_deserializer<Tail...>::deserialize(in, param);
-        }
-    }
-};
-
-InStreams& deserialize(InStreams& in, KeyParameter* param) {
-    in.elements.read(reinterpret_cast<char*>(&param->tag), sizeof(Tag));
-    return choose_deserializer<all_tags_t>::deserialize(in, param);
-}
-
-std::istream& deserialize(std::istream& in, std::vector<KeyParameter>* params) {
-    uint32_t indirect_size = 0;
-    in.read(reinterpret_cast<char*>(&indirect_size), sizeof(uint32_t));
-    std::string indirect_buffer(indirect_size, '\0');
-    if (indirect_buffer.size() != indirect_size) {
-        in.setstate(std::ios_base::badbit);
-        return in;
-    }
-    in.read(&indirect_buffer[0], indirect_buffer.size());
-
-    uint32_t element_count = 0;
-    in.read(reinterpret_cast<char*>(&element_count), sizeof(uint32_t));
-    uint32_t elements_size = 0;
-    in.read(reinterpret_cast<char*>(&elements_size), sizeof(uint32_t));
-
-    std::string elements_buffer(elements_size, '\0');
-    if(elements_buffer.size() != elements_size) {
-        in.setstate(std::ios_base::badbit);
-        return in;
-    }
-    in.read(&elements_buffer[0], elements_buffer.size());
-
-    if (in.bad()) return in;
-
-    // TODO write one-shot stream buffer to avoid copying here
-    std::stringstream indirect(indirect_buffer);
-    std::stringstream elements(elements_buffer);
-    InStreams streams = { indirect, elements };
-
-    params->resize(element_count);
-
-    for (uint32_t i = 0; i < element_count; ++i) {
-        deserialize(streams, &(*params)[i]);
-    }
-    return in;
-}
-void AuthorizationSet::Serialize(std::ostream* out) const {
-    serialize(*out, data_);
-}
-void AuthorizationSet::Deserialize(std::istream* in) {
-    deserialize(*in, &data_);
-}
-
-}  // namespace keystore
diff --git a/keystore/blob.cpp b/keystore/blob.cpp
index b901553..f08e08d 100644
--- a/keystore/blob.cpp
+++ b/keystore/blob.cpp
@@ -28,6 +28,15 @@
 
 #include "keystore_utils.h"
 
+#include <openssl/evp.h>
+
+#include <istream>
+#include <ostream>
+#include <streambuf>
+#include <string>
+
+#include <android-base/logging.h>
+
 namespace {
 
 constexpr size_t kGcmIvSizeBytes = 96 / 8;
@@ -128,11 +137,60 @@
     return ResponseCode::NO_ERROR;
 }
 
+class ArrayStreamBuffer : public std::streambuf {
+  public:
+    template <typename T, size_t size> ArrayStreamBuffer(const T (&data)[size]) {
+        static_assert(sizeof(T) == 1, "Array element size too large");
+        std::streambuf::char_type* d = const_cast<std::streambuf::char_type*>(
+            reinterpret_cast<const std::streambuf::char_type*>(&data[0]));
+        setg(d, d, d + size);
+        setp(d, d + size);
+    }
+
+  protected:
+    pos_type seekoff(off_type off, std::ios_base::seekdir dir,
+                     std::ios_base::openmode which = std::ios_base::in |
+                                                     std::ios_base::out) override {
+        bool in = which & std::ios_base::in;
+        bool out = which & std::ios_base::out;
+        if ((!in && !out) || (in && out && dir == std::ios_base::cur)) return -1;
+        std::streambuf::char_type* newPosPtr;
+        switch (dir) {
+        case std::ios_base::beg:
+            newPosPtr = pbase();
+            break;
+        case std::ios_base::cur:
+            // if dir == cur then in xor out due to
+            // if ((!in && !out) || (in && out && dir == std::ios_base::cur)) return -1; above
+            if (in)
+                newPosPtr = gptr();
+            else
+                newPosPtr = pptr();
+            break;
+        case std::ios_base::end:
+            // in and out bounds are the same and cannot change, so we can take either range
+            // regardless of the value of "which"
+            newPosPtr = epptr();
+            break;
+        }
+        newPosPtr += off;
+        if (newPosPtr < pbase() || newPosPtr > epptr()) return -1;
+        if (in) {
+            gbump(newPosPtr - gptr());
+        }
+        if (out) {
+            pbump(newPosPtr - pptr());
+        }
+        return newPosPtr - pbase();
+    }
+};
+
 }  // namespace
 
 Blob::Blob(const uint8_t* value, size_t valueLength, const uint8_t* info, uint8_t infoLength,
            BlobType type) {
-    memset(&mBlob, 0, sizeof(mBlob));
+    mBlob = std::make_unique<blobv3>();
+    memset(mBlob.get(), 0, sizeof(blobv3));
     if (valueLength > kValueSize) {
         valueLength = kValueSize;
         ALOGW("Provided blob length too large");
@@ -141,44 +199,76 @@
         infoLength = kValueSize - valueLength;
         ALOGW("Provided info length too large");
     }
-    mBlob.length = valueLength;
-    memcpy(mBlob.value, value, valueLength);
+    mBlob->length = valueLength;
+    memcpy(mBlob->value, value, valueLength);
 
-    mBlob.info = infoLength;
-    memcpy(mBlob.value + valueLength, info, infoLength);
+    mBlob->info = infoLength;
+    memcpy(mBlob->value + valueLength, info, infoLength);
 
-    mBlob.version = CURRENT_BLOB_VERSION;
-    mBlob.type = uint8_t(type);
+    mBlob->version = CURRENT_BLOB_VERSION;
+    mBlob->type = uint8_t(type);
 
     if (type == TYPE_MASTER_KEY) {
-        mBlob.flags = KEYSTORE_FLAG_ENCRYPTED;
+        mBlob->flags = KEYSTORE_FLAG_ENCRYPTED;
     } else {
-        mBlob.flags = KEYSTORE_FLAG_NONE;
+        mBlob->flags = KEYSTORE_FLAG_NONE;
     }
 }
 
 Blob::Blob(blobv3 b) {
-    mBlob = b;
+    mBlob = std::make_unique<blobv3>(b);
 }
 
 Blob::Blob() {
-    memset(&mBlob, 0, sizeof(mBlob));
+    if (mBlob) *mBlob = {};
+}
+
+Blob::Blob(const Blob& rhs) {
+    if (rhs.mBlob) {
+        mBlob = std::make_unique<blobv3>(*rhs.mBlob);
+    }
+}
+
+Blob::Blob(Blob&& rhs) : mBlob(std::move(rhs.mBlob)) {}
+
+Blob& Blob::operator=(const Blob& rhs) {
+    if (&rhs != this) {
+        if (mBlob) *mBlob = {};
+        if (rhs) {
+            mBlob = std::make_unique<blobv3>(*rhs.mBlob);
+        } else {
+            mBlob = {};
+        }
+    }
+    return *this;
+}
+
+Blob& Blob::operator=(Blob&& rhs) {
+    if (mBlob) *mBlob = {};
+    mBlob = std::move(rhs.mBlob);
+    return *this;
+}
+
+template <typename BlobType> static bool rawBlobIsEncrypted(const BlobType& blob) {
+    if (blob.version < 2) return true;
+
+    return blob.flags & (KEYSTORE_FLAG_ENCRYPTED | KEYSTORE_FLAG_SUPER_ENCRYPTED);
 }
 
 bool Blob::isEncrypted() const {
-    if (mBlob.version < 2) {
+    if (mBlob->version < 2) {
         return true;
     }
 
-    return mBlob.flags & KEYSTORE_FLAG_ENCRYPTED;
+    return mBlob->flags & KEYSTORE_FLAG_ENCRYPTED;
 }
 
 bool Blob::isSuperEncrypted() const {
-    return mBlob.flags & KEYSTORE_FLAG_SUPER_ENCRYPTED;
+    return mBlob->flags & KEYSTORE_FLAG_SUPER_ENCRYPTED;
 }
 
 bool Blob::isCriticalToDeviceEncryption() const {
-    return mBlob.flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
+    return mBlob->flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
 }
 
 inline uint8_t setFlag(uint8_t flags, bool set, KeyStoreFlag flag) {
@@ -186,83 +276,106 @@
 }
 
 void Blob::setEncrypted(bool encrypted) {
-    mBlob.flags = setFlag(mBlob.flags, encrypted, KEYSTORE_FLAG_ENCRYPTED);
+    mBlob->flags = setFlag(mBlob->flags, encrypted, KEYSTORE_FLAG_ENCRYPTED);
 }
 
 void Blob::setSuperEncrypted(bool superEncrypted) {
-    mBlob.flags = setFlag(mBlob.flags, superEncrypted, KEYSTORE_FLAG_SUPER_ENCRYPTED);
+    mBlob->flags = setFlag(mBlob->flags, superEncrypted, KEYSTORE_FLAG_SUPER_ENCRYPTED);
 }
 
 void Blob::setCriticalToDeviceEncryption(bool critical) {
-    mBlob.flags = setFlag(mBlob.flags, critical, KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
+    mBlob->flags = setFlag(mBlob->flags, critical, KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
 }
 
 void Blob::setFallback(bool fallback) {
     if (fallback) {
-        mBlob.flags |= KEYSTORE_FLAG_FALLBACK;
+        mBlob->flags |= KEYSTORE_FLAG_FALLBACK;
     } else {
-        mBlob.flags &= ~KEYSTORE_FLAG_FALLBACK;
+        mBlob->flags &= ~KEYSTORE_FLAG_FALLBACK;
     }
 }
 
-ResponseCode Blob::writeBlob(const std::string& filename, const uint8_t* aes_key, State state,
-                             Entropy* entropy) {
+static ResponseCode writeBlob(const std::string& filename, Blob blob, blobv3* rawBlob,
+                              const uint8_t* aes_key, State state, Entropy* entropy) {
     ALOGV("writing blob %s", filename.c_str());
 
-    const size_t dataLength = mBlob.length;
-    mBlob.length = htonl(mBlob.length);
+    const size_t dataLength = rawBlob->length;
+    rawBlob->length = htonl(rawBlob->length);
 
-    if (isEncrypted() || isSuperEncrypted()) {
+    if (blob.isEncrypted() || blob.isSuperEncrypted()) {
         if (state != STATE_NO_ERROR) {
             ALOGD("couldn't insert encrypted blob while not unlocked");
             return ResponseCode::LOCKED;
         }
 
-        memset(mBlob.initialization_vector, 0, AES_BLOCK_SIZE);
-        if (!entropy->generate_random_data(mBlob.initialization_vector, kGcmIvSizeBytes)) {
+        memset(rawBlob->initialization_vector, 0, AES_BLOCK_SIZE);
+        if (!entropy->generate_random_data(rawBlob->initialization_vector, kGcmIvSizeBytes)) {
             ALOGW("Could not read random data for: %s", filename.c_str());
             return ResponseCode::SYSTEM_ERROR;
         }
 
-        auto rc = AES_gcm_encrypt(mBlob.value /* in */, mBlob.value /* out */, dataLength, aes_key,
-                                  mBlob.initialization_vector, mBlob.aead_tag);
+        auto rc = AES_gcm_encrypt(rawBlob->value /* in */, rawBlob->value /* out */, dataLength,
+                                  aes_key, rawBlob->initialization_vector, rawBlob->aead_tag);
         if (rc != ResponseCode::NO_ERROR) return rc;
     }
 
-    size_t fileLength = offsetof(blobv3, value) + dataLength + mBlob.info;
+    size_t fileLength = offsetof(blobv3, value) + dataLength + rawBlob->info;
 
-    char tmpFileName[] = ".tmpXXXXXX";
-    int out = TEMP_FAILURE_RETRY(mkstemp(tmpFileName));
+    int out =
+        TEMP_FAILURE_RETRY(open(filename.c_str(), O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
     if (out < 0) {
-        ALOGW("could not open temporary file: %s: %s", tmpFileName, strerror(errno));
+        ALOGW("could not open file: %s: %s", filename.c_str(), strerror(errno));
         return ResponseCode::SYSTEM_ERROR;
     }
 
-    const size_t writtenBytes = writeFully(out, (uint8_t*)&mBlob, fileLength);
+    const size_t writtenBytes = writeFully(out, reinterpret_cast<uint8_t*>(rawBlob), fileLength);
     if (close(out) != 0) {
         return ResponseCode::SYSTEM_ERROR;
     }
     if (writtenBytes != fileLength) {
         ALOGW("blob not fully written %zu != %zu", writtenBytes, fileLength);
-        unlink(tmpFileName);
-        return ResponseCode::SYSTEM_ERROR;
-    }
-    if (rename(tmpFileName, filename.c_str()) == -1) {
-        ALOGW("could not rename blob to %s: %s", filename.c_str(), strerror(errno));
+        unlink(filename.c_str());
         return ResponseCode::SYSTEM_ERROR;
     }
     return ResponseCode::NO_ERROR;
 }
 
+ResponseCode LockedKeyBlobEntry::writeBlobs(Blob keyBlob, Blob characteristicsBlob,
+                                            const uint8_t* aes_key, State state,
+                                            Entropy* entropy) const {
+    if (entry_ == nullptr) {
+        return ResponseCode::SYSTEM_ERROR;
+    }
+    ResponseCode rc;
+    if (keyBlob) {
+        blobv3* rawBlob = keyBlob.mBlob.get();
+        rc = writeBlob(entry_->getKeyBlobPath(), std::move(keyBlob), rawBlob, aes_key, state,
+                       entropy);
+        if (rc != ResponseCode::NO_ERROR) {
+            return rc;
+        }
+    }
+
+    if (characteristicsBlob) {
+        blobv3* rawBlob = characteristicsBlob.mBlob.get();
+        rc = writeBlob(entry_->getCharacteristicsBlobPath(), std::move(characteristicsBlob),
+                       rawBlob, aes_key, state, entropy);
+    }
+    return rc;
+}
+
 ResponseCode Blob::readBlob(const std::string& filename, const uint8_t* aes_key, State state) {
+    ResponseCode rc;
     ALOGV("reading blob %s", filename.c_str());
+    std::unique_ptr<blobv3> rawBlob = std::make_unique<blobv3>();
+
     const int in = TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY));
     if (in < 0) {
         return (errno == ENOENT) ? ResponseCode::KEY_NOT_FOUND : ResponseCode::SYSTEM_ERROR;
     }
 
     // fileLength may be less than sizeof(mBlob)
-    const size_t fileLength = readFully(in, (uint8_t*)&mBlob, sizeof(mBlob));
+    const size_t fileLength = readFully(in, (uint8_t*)rawBlob.get(), sizeof(blobv3));
     if (close(in) != 0) {
         return ResponseCode::SYSTEM_ERROR;
     }
@@ -271,67 +384,329 @@
         return ResponseCode::VALUE_CORRUPTED;
     }
 
-    if ((isEncrypted() || isSuperEncrypted())) {
-        if (state == STATE_LOCKED) return ResponseCode::LOCKED;
+    if (rawBlobIsEncrypted(*rawBlob)) {
+        if (state == STATE_LOCKED) {
+            mBlob = std::move(rawBlob);
+            return ResponseCode::LOCKED;
+        }
         if (state == STATE_UNINITIALIZED) return ResponseCode::UNINITIALIZED;
     }
 
     if (fileLength < offsetof(blobv3, value)) return ResponseCode::VALUE_CORRUPTED;
 
-    if (mBlob.version == 3) {
-        const ssize_t encryptedLength = ntohl(mBlob.length);
+    if (rawBlob->version == 3) {
+        const ssize_t encryptedLength = ntohl(rawBlob->length);
 
-        if (isEncrypted() || isSuperEncrypted()) {
-            auto rc = AES_gcm_decrypt(mBlob.value /* in */, mBlob.value /* out */, encryptedLength,
-                                      aes_key, mBlob.initialization_vector, mBlob.aead_tag);
+        if (rawBlobIsEncrypted(*rawBlob)) {
+            rc = AES_gcm_decrypt(rawBlob->value /* in */, rawBlob->value /* out */, encryptedLength,
+                                 aes_key, rawBlob->initialization_vector, rawBlob->aead_tag);
             if (rc != ResponseCode::NO_ERROR) return rc;
         }
-    } else if (mBlob.version < 3) {
-        blobv2& blob = reinterpret_cast<blobv2&>(mBlob);
+    } else if (rawBlob->version < 3) {
+        blobv2& v2blob = reinterpret_cast<blobv2&>(*rawBlob);
         const size_t headerLength = offsetof(blobv2, encrypted);
-        const ssize_t encryptedLength = fileLength - headerLength - blob.info;
+        const ssize_t encryptedLength = fileLength - headerLength - v2blob.info;
         if (encryptedLength < 0) return ResponseCode::VALUE_CORRUPTED;
 
-        if (isEncrypted() || isSuperEncrypted()) {
+        if (rawBlobIsEncrypted(*rawBlob)) {
             if (encryptedLength % AES_BLOCK_SIZE != 0) {
                 return ResponseCode::VALUE_CORRUPTED;
             }
 
             AES_KEY key;
             AES_set_decrypt_key(aes_key, kAesKeySize * 8, &key);
-            AES_cbc_encrypt(blob.encrypted, blob.encrypted, encryptedLength, &key, blob.vector,
-                            AES_DECRYPT);
+            AES_cbc_encrypt(v2blob.encrypted, v2blob.encrypted, encryptedLength, &key,
+                            v2blob.vector, AES_DECRYPT);
             key = {};  // clear key
 
             uint8_t computedDigest[MD5_DIGEST_LENGTH];
             ssize_t digestedLength = encryptedLength - MD5_DIGEST_LENGTH;
-            MD5(blob.digested, digestedLength, computedDigest);
-            if (memcmp(blob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) {
+            MD5(v2blob.digested, digestedLength, computedDigest);
+            if (memcmp(v2blob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) {
                 return ResponseCode::VALUE_CORRUPTED;
             }
         }
     }
 
-    const ssize_t maxValueLength = fileLength - offsetof(blobv3, value) - mBlob.info;
-    mBlob.length = ntohl(mBlob.length);
-    if (mBlob.length < 0 || mBlob.length > maxValueLength ||
-        mBlob.length + mBlob.info + AES_BLOCK_SIZE > static_cast<ssize_t>(sizeof(mBlob.value))) {
+    const ssize_t maxValueLength = fileLength - offsetof(blobv3, value) - rawBlob->info;
+    rawBlob->length = ntohl(rawBlob->length);
+    if (rawBlob->length < 0 || rawBlob->length > maxValueLength ||
+        rawBlob->length + rawBlob->info + AES_BLOCK_SIZE >
+            static_cast<ssize_t>(sizeof(rawBlob->value))) {
         return ResponseCode::VALUE_CORRUPTED;
     }
 
-    if (mBlob.info != 0 && mBlob.version < 3) {
+    if (rawBlob->info != 0 && rawBlob->version < 3) {
         // move info from after padding to after data
-        memmove(mBlob.value + mBlob.length, mBlob.value + maxValueLength, mBlob.info);
+        memmove(rawBlob->value + rawBlob->length, rawBlob->value + maxValueLength, rawBlob->info);
     }
 
+    mBlob = std::move(rawBlob);
     return ResponseCode::NO_ERROR;
 }
 
+std::tuple<ResponseCode, Blob, Blob> LockedKeyBlobEntry::readBlobs(const uint8_t* aes_key,
+                                                                   State state) const {
+    std::tuple<ResponseCode, Blob, Blob> result;
+    auto& [rc, keyBlob, characteristicsBlob] = result;
+    if (entry_ == nullptr) return rc = ResponseCode::SYSTEM_ERROR, result;
+
+    rc = keyBlob.readBlob(entry_->getKeyBlobPath(), aes_key, state);
+    if (rc != ResponseCode::NO_ERROR && rc != ResponseCode::UNINITIALIZED) {
+        return result;
+    }
+
+    if (entry_->hasCharacteristicsBlob()) {
+        characteristicsBlob.readBlob(entry_->getCharacteristicsBlobPath(), aes_key, state);
+    }
+    return result;
+}
+
+ResponseCode LockedKeyBlobEntry::deleteBlobs() const {
+    if (entry_ == nullptr) return ResponseCode::NO_ERROR;
+
+    // always try to delete both
+    ResponseCode rc1 = (unlink(entry_->getKeyBlobPath().c_str()) && errno != ENOENT)
+                           ? ResponseCode::SYSTEM_ERROR
+                           : ResponseCode::NO_ERROR;
+    if (rc1 != ResponseCode::NO_ERROR) {
+        ALOGW("Failed to delete key blob file \"%s\"", entry_->getKeyBlobPath().c_str());
+    }
+    ResponseCode rc2 = (unlink(entry_->getCharacteristicsBlobPath().c_str()) && errno != ENOENT)
+                           ? ResponseCode::SYSTEM_ERROR
+                           : ResponseCode::NO_ERROR;
+    if (rc2 != ResponseCode::NO_ERROR) {
+        ALOGW("Failed to delete key characteristics file \"%s\"",
+              entry_->getCharacteristicsBlobPath().c_str());
+    }
+    // then report the first error that occured
+    if (rc1 != ResponseCode::NO_ERROR) return rc1;
+    return rc2;
+}
+
 keystore::SecurityLevel Blob::getSecurityLevel() const {
-    return keystore::flagsToSecurityLevel(mBlob.flags);
+    return keystore::flagsToSecurityLevel(mBlob->flags);
 }
 
 void Blob::setSecurityLevel(keystore::SecurityLevel secLevel) {
-    mBlob.flags &= ~(KEYSTORE_FLAG_FALLBACK | KEYSTORE_FLAG_STRONGBOX);
-    mBlob.flags |= keystore::securityLevelToFlags(secLevel);
+    mBlob->flags &= ~(KEYSTORE_FLAG_FALLBACK | KEYSTORE_FLAG_STRONGBOX);
+    mBlob->flags |= keystore::securityLevelToFlags(secLevel);
+}
+
+std::tuple<bool, keystore::AuthorizationSet, keystore::AuthorizationSet>
+Blob::getKeyCharacteristics() const {
+    std::tuple<bool, keystore::AuthorizationSet, keystore::AuthorizationSet> result;
+    auto& [success, hwEnforced, swEnforced] = result;
+    success = false;
+    ArrayStreamBuffer buf(mBlob->value);
+    std::istream in(&buf);
+
+    // only the characteristics cache has both sets
+    if (getType() == TYPE_KEY_CHARACTERISTICS_CACHE) {
+        hwEnforced.Deserialize(&in);
+    } else if (getType() != TYPE_KEY_CHARACTERISTICS) {
+        // if its not the cache and not the legacy characteristics file we have no business
+        // here
+        return result;
+    }
+    swEnforced.Deserialize(&in);
+    success = !in.bad();
+
+    return result;
+}
+bool Blob::putKeyCharacteristics(const keystore::AuthorizationSet& hwEnforced,
+                                 const keystore::AuthorizationSet& swEnforced) {
+    if (!mBlob) mBlob = std::make_unique<blobv3>();
+    mBlob->version = CURRENT_BLOB_VERSION;
+    ArrayStreamBuffer buf(mBlob->value);
+    std::ostream out(&buf);
+    hwEnforced.Serialize(&out);
+    swEnforced.Serialize(&out);
+    if (out.bad()) return false;
+    setType(TYPE_KEY_CHARACTERISTICS_CACHE);
+    mBlob->length = out.tellp();
+    return true;
+}
+
+void LockedKeyBlobEntry::put(const KeyBlobEntry& entry) {
+    std::unique_lock<std::mutex> lock(locked_blobs_mutex_);
+    locked_blobs_.erase(entry);
+    lock.unlock();
+    locked_blobs_mutex_cond_var_.notify_all();
+}
+
+LockedKeyBlobEntry::~LockedKeyBlobEntry() {
+    if (entry_ != nullptr) put(*entry_);
+}
+
+LockedKeyBlobEntry LockedKeyBlobEntry::get(KeyBlobEntry entry) {
+    std::unique_lock<std::mutex> lock(locked_blobs_mutex_);
+    locked_blobs_mutex_cond_var_.wait(
+        lock, [&] { return locked_blobs_.find(entry) == locked_blobs_.end(); });
+    auto [iterator, success] = locked_blobs_.insert(std::move(entry));
+    if (!success) return {};
+    return LockedKeyBlobEntry(*iterator);
+}
+
+std::set<KeyBlobEntry> LockedKeyBlobEntry::locked_blobs_;
+std::mutex LockedKeyBlobEntry::locked_blobs_mutex_;
+std::condition_variable LockedKeyBlobEntry::locked_blobs_mutex_cond_var_;
+
+/* Here is the encoding of key names. This is necessary in order to allow arbitrary
+ * characters in key names. Characters in [0-~] are not encoded. Others are encoded
+ * into two bytes. The first byte is one of [+-.] which represents the first
+ * two bits of the character. The second byte encodes the rest of the bits into
+ * [0-o]. Therefore in the worst case the length of a key gets doubled. Note
+ * that Base64 cannot be used here due to the need of prefix match on keys. */
+
+static std::string encodeKeyName(const std::string& keyName) {
+    std::string encodedName;
+    encodedName.reserve(keyName.size() * 2);
+    auto in = keyName.begin();
+    while (in != keyName.end()) {
+        if (*in < '0' || *in > '~') {
+            encodedName.append(1, '+' + (uint8_t(*in) >> 6));
+            encodedName.append(1, '0' + (*in & 0x3F));
+        } else {
+            encodedName.append(1, *in);
+        }
+        ++in;
+    }
+    return encodedName;
+}
+
+static std::string decodeKeyName(const std::string& encodedName) {
+    std::string decodedName;
+    decodedName.reserve(encodedName.size());
+    auto in = encodedName.begin();
+    bool multichar = false;
+    char c;
+    while (in != encodedName.end()) {
+        if (multichar) {
+            multichar = false;
+            decodedName.append(1, c | *in);
+        } else if (*in >= '+' && *in <= '.') {
+            multichar = true;
+            c = (*in - '+') << 6;
+        } else {
+            decodedName.append(1, *in);
+        }
+        ++in;
+    }
+    // mulitchars at the end get truncated
+    return decodedName;
+}
+
+std::string KeyBlobEntry::getKeyBlobBaseName() const {
+    std::stringstream s;
+    if (masterkey_) {
+        s << alias_;
+    } else {
+        s << uid_ << "_" << encodeKeyName(alias_);
+    }
+    return s.str();
+}
+
+std::string KeyBlobEntry::getKeyBlobPath() const {
+    std::stringstream s;
+    if (masterkey_) {
+        s << user_dir_ << "/" << alias_;
+    } else {
+        s << user_dir_ << "/" << uid_ << "_" << encodeKeyName(alias_);
+    }
+    return s.str();
+}
+
+std::string KeyBlobEntry::getCharacteristicsBlobBaseName() const {
+    std::stringstream s;
+    if (!masterkey_) s << "." << uid_ << "_chr_" << encodeKeyName(alias_);
+    return s.str();
+}
+
+std::string KeyBlobEntry::getCharacteristicsBlobPath() const {
+    std::stringstream s;
+    if (!masterkey_)
+        s << user_dir_ << "/"
+          << "." << uid_ << "_chr_" << encodeKeyName(alias_);
+    return s.str();
+}
+
+bool KeyBlobEntry::hasKeyBlob() const {
+    return !access(getKeyBlobPath().c_str(), R_OK | W_OK);
+}
+bool KeyBlobEntry::hasCharacteristicsBlob() const {
+    return !access(getCharacteristicsBlobPath().c_str(), R_OK | W_OK);
+}
+
+static std::tuple<bool, uid_t, std::string> filename2UidAlias(const std::string& filepath) {
+    std::tuple<bool, uid_t, std::string> result;
+
+    auto& [success, uid, alias] = result;
+
+    success = false;
+
+    auto filenamebase = filepath.find_last_of('/');
+    std::string filename =
+        filenamebase == std::string::npos ? filepath : filepath.substr(filenamebase + 1);
+
+    if (filename[0] == '.') return result;
+
+    auto sep = filename.find('_');
+    if (sep == std::string::npos) return result;
+
+    std::stringstream s(filename.substr(0, sep));
+    s >> uid;
+    if (!s) return result;
+
+    alias = decodeKeyName(filename.substr(sep + 1));
+    success = true;
+    return result;
+}
+
+std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>>
+LockedKeyBlobEntry::list(const std::string& user_dir,
+                         std::function<bool(uid_t, const std::string&)> filter) {
+    std::list<LockedKeyBlobEntry> matches;
+
+    // This is a fence against any concurrent database accesses during database iteration.
+    // Only the keystore thread can lock entries. So it cannot be starved
+    // by workers grabbing new individual locks. We just wait here until all
+    // workers have relinquished their locked files.
+    std::unique_lock<std::mutex> lock(locked_blobs_mutex_);
+    locked_blobs_mutex_cond_var_.wait(lock, [&] { return locked_blobs_.empty(); });
+
+    DIR* dir = opendir(user_dir.c_str());
+    if (!dir) {
+        ALOGW("can't open directory for user: %s", strerror(errno));
+        return std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>&&>{ResponseCode::SYSTEM_ERROR,
+                                                                         std::move(matches)};
+    }
+
+    struct dirent* file;
+    while ((file = readdir(dir)) != nullptr) {
+        // We only care about files.
+        if (file->d_type != DT_REG) {
+            continue;
+        }
+
+        // Skip anything that starts with a "."
+        if (file->d_name[0] == '.') {
+            continue;
+        }
+
+        auto [success, uid, alias] = filename2UidAlias(file->d_name);
+
+        if (!success) {
+            ALOGW("could not parse key filename \"%s\"", file->d_name);
+            continue;
+        }
+
+        if (!filter(uid, alias)) continue;
+
+        auto [iterator, dummy] = locked_blobs_.emplace(alias, user_dir, uid);
+        matches.push_back(*iterator);
+    }
+    closedir(dir);
+    return std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>&&>{ResponseCode::NO_ERROR,
+                                                                     std::move(matches)};
 }
diff --git a/keystore/blob.h b/keystore/blob.h
index 665e07a..5cd1b90 100644
--- a/keystore/blob.h
+++ b/keystore/blob.h
@@ -22,8 +22,14 @@
 #include <openssl/aes.h>
 #include <openssl/md5.h>
 
+#include <condition_variable>
+#include <functional>
 #include <keystore/keymaster_types.h>
 #include <keystore/keystore.h>
+#include <list>
+#include <mutex>
+#include <set>
+#include <sstream>
 
 constexpr size_t kValueSize = 32768;
 constexpr size_t kAesKeySize = 128 / 8;
@@ -80,27 +86,45 @@
     TYPE_KEY_PAIR = 3,
     TYPE_KEYMASTER_10 = 4,
     TYPE_KEY_CHARACTERISTICS = 5,
+    TYPE_KEY_CHARACTERISTICS_CACHE = 6,
 } BlobType;
 
 class Entropy;
+class LockedKeyBlobEntry;
 
+/**
+ * The Blob represents the content of a KeyBlobEntry.
+ *
+ * BEWARE: It is only save to call any member function of a Blob b if bool(b) yields true.
+ *         Exceptions are putKeyCharacteristics(), the assignment operators and operator bool.
+ */
 class Blob {
+    friend LockedKeyBlobEntry;
+
   public:
     Blob(const uint8_t* value, size_t valueLength, const uint8_t* info, uint8_t infoLength,
          BlobType type);
     explicit Blob(blobv3 b);
     Blob();
+    Blob(const Blob& rhs);
+    Blob(Blob&& rhs);
 
-    ~Blob() { mBlob = {}; }
+    ~Blob() {
+        if (mBlob) *mBlob = {};
+    }
 
-    const uint8_t* getValue() const { return mBlob.value; }
+    Blob& operator=(const Blob& rhs);
+    Blob& operator=(Blob&& rhs);
+    operator bool() const { return bool(mBlob); }
 
-    int32_t getLength() const { return mBlob.length; }
+    const uint8_t* getValue() const { return mBlob->value; }
 
-    const uint8_t* getInfo() const { return mBlob.value + mBlob.length; }
-    uint8_t getInfoLength() const { return mBlob.info; }
+    int32_t getLength() const { return mBlob->length; }
 
-    uint8_t getVersion() const { return mBlob.version; }
+    const uint8_t* getInfo() const { return mBlob->value + mBlob->length; }
+    uint8_t getInfoLength() const { return mBlob->info; }
+
+    uint8_t getVersion() const { return mBlob->version; }
 
     bool isEncrypted() const;
     void setEncrypted(bool encrypted);
@@ -111,22 +135,141 @@
     bool isCriticalToDeviceEncryption() const;
     void setCriticalToDeviceEncryption(bool critical);
 
-    bool isFallback() const { return mBlob.flags & KEYSTORE_FLAG_FALLBACK; }
+    bool isFallback() const { return mBlob->flags & KEYSTORE_FLAG_FALLBACK; }
     void setFallback(bool fallback);
 
-    void setVersion(uint8_t version) { mBlob.version = version; }
-    BlobType getType() const { return BlobType(mBlob.type); }
-    void setType(BlobType type) { mBlob.type = uint8_t(type); }
+    void setVersion(uint8_t version) { mBlob->version = version; }
+    BlobType getType() const { return BlobType(mBlob->type); }
+    void setType(BlobType type) { mBlob->type = uint8_t(type); }
 
     keystore::SecurityLevel getSecurityLevel() const;
     void setSecurityLevel(keystore::SecurityLevel);
 
-    ResponseCode writeBlob(const std::string& filename, const uint8_t* aes_key, State state,
-                           Entropy* entropy);
-    ResponseCode readBlob(const std::string& filename, const uint8_t* aes_key, State state);
+    std::tuple<bool, keystore::AuthorizationSet, keystore::AuthorizationSet>
+    getKeyCharacteristics() const;
+
+    bool putKeyCharacteristics(const keystore::AuthorizationSet& hwEnforced,
+                               const keystore::AuthorizationSet& swEnforced);
 
   private:
-    blobv3 mBlob;
+    std::unique_ptr<blobv3> mBlob;
+
+    ResponseCode readBlob(const std::string& filename, const uint8_t* aes_key, State state);
+};
+
+/**
+ * A KeyBlobEntry represents a full qualified key blob as known by Keystore. The key blob
+ * is given by the uid of the owning app and the alias used by the app to refer to this key.
+ * The user_dir_ is technically implied by the uid, but computation of the user directory is
+ * done in the user state database. Which is why we also cache it here.
+ *
+ * The KeyBlobEntry knows the location of the key blob files (which may include a characteristics
+ * cache file) but does not allow read or write access to the content. It also does not imply
+ * the existence of the files.
+ *
+ * KeyBlobEntry abstracts, to some extent, from the the file system based storage of key blobs.
+ * An evolution of KeyBlobEntry may be used for key blob storage based on a back end other than
+ * file system, e.g., SQL database or other.
+ *
+ * For access to the key blob content the programmer has to acquire a LockedKeyBlobEntry (see
+ * below).
+ */
+class KeyBlobEntry {
+  private:
+    std::string alias_;
+    std::string user_dir_;
+    uid_t uid_;
+    bool masterkey_;
+
+  public:
+    KeyBlobEntry(std::string alias, std::string user_dir, uid_t uid, bool masterkey = false)
+        : alias_(std::move(alias)), user_dir_(std::move(user_dir)), uid_(uid),
+          masterkey_(masterkey) {}
+
+    std::string getKeyBlobBaseName() const;
+    std::string getKeyBlobPath() const;
+
+    std::string getCharacteristicsBlobBaseName() const;
+    std::string getCharacteristicsBlobPath() const;
+
+    bool hasKeyBlob() const;
+    bool hasCharacteristicsBlob() const;
+
+    bool operator<(const KeyBlobEntry& rhs) const {
+        return std::tie(alias_, user_dir_, uid_) < std::tie(rhs.alias_, rhs.user_dir_, uid_);
+    }
+    bool operator==(const KeyBlobEntry& rhs) const {
+        return std::tie(alias_, user_dir_, uid_) == std::tie(rhs.alias_, rhs.user_dir_, uid_);
+    }
+    bool operator!=(const KeyBlobEntry& rhs) const { return !(*this == rhs); }
+
+    inline const std::string& alias() const { return alias_; }
+    inline const std::string& user_dir() const { return user_dir_; }
+    inline uid_t uid() const { return uid_; }
+};
+
+/**
+ * The LockedKeyBlobEntry is a proxy object to KeyBlobEntry that expresses exclusive ownership
+ * of a KeyBlobEntry. LockedKeyBlobEntries can be acquired by calling
+ * LockedKeyBlobEntry::get() or LockedKeyBlobEntry::list().
+ *
+ * LockedKeyBlobEntries are movable but not copyable. By convention they can only
+ * be taken by the dispatcher thread of keystore, but not by any keymaster worker thread.
+ * The dispatcher thread may transfer ownership of a locked entry to a keymaster worker thread.
+ *
+ * Locked entries are tracked on the stack or as members of movable functor objects passed to the
+ * keymaster worker request queues. Locks are relinquished as the locked entry gets destroyed, e.g.,
+ * when it goes out of scope or when the owning request functor gets destroyed.
+ *
+ * LockedKeyBlobEntry::list(), which must only be called by the dispatcher, blocks until all
+ * LockedKeyBlobEntries have been destroyed. Thereby list acts as a fence to make sure it gets a
+ * consistent view of the key blob database. Under the assumption that keymaster worker requests
+ * cannot run or block indefinitely and cannot grab new locked entries, progress is guaranteed.
+ * It then grabs locked entries in accordance with the given filter rule.
+ *
+ * LockedKeyBlobEntry allow access to the proxied KeyBlobEntry interface through the operator->.
+ * They add additional functionality to access and modify the key blob's content on disk.
+ * LockedKeyBlobEntry ensures atomic operations on the persistently stored key blobs on a per
+ * entry granularity.
+ */
+class LockedKeyBlobEntry {
+  private:
+    static std::set<KeyBlobEntry> locked_blobs_;
+    static std::mutex locked_blobs_mutex_;
+    static std::condition_variable locked_blobs_mutex_cond_var_;
+
+    const KeyBlobEntry* entry_;
+    LockedKeyBlobEntry(const KeyBlobEntry& entry) : entry_(&entry) {}
+
+    static void put(const KeyBlobEntry& entry);
+    LockedKeyBlobEntry(const LockedKeyBlobEntry&) = delete;
+    LockedKeyBlobEntry& operator=(const LockedKeyBlobEntry&) = delete;
+
+  public:
+    LockedKeyBlobEntry() : entry_(nullptr){};
+    ~LockedKeyBlobEntry();
+    LockedKeyBlobEntry(LockedKeyBlobEntry&& rhs) : entry_(rhs.entry_) { rhs.entry_ = nullptr; }
+    LockedKeyBlobEntry& operator=(LockedKeyBlobEntry&& rhs) {
+        // as dummy goes out of scope it relinquishes the lock on this
+        LockedKeyBlobEntry dummy(std::move(*this));
+        entry_ = rhs.entry_;
+        rhs.entry_ = nullptr;
+        return *this;
+    }
+    static LockedKeyBlobEntry get(KeyBlobEntry entry);
+    static std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>>
+    list(const std::string& user_dir,
+         std::function<bool(uid_t, const std::string&)> filter =
+             [](uid_t, const std::string&) -> bool { return true; });
+
+    ResponseCode writeBlobs(Blob keyBlob, Blob characteristicsBlob, const uint8_t* aes_key,
+                            State state, Entropy* entorpy) const;
+    std::tuple<ResponseCode, Blob, Blob> readBlobs(const uint8_t* aes_key, State state) const;
+    ResponseCode deleteBlobs() const;
+
+    inline operator bool() const { return entry_ != nullptr; }
+    inline const KeyBlobEntry& operator*() const { return *entry_; }
+    inline const KeyBlobEntry* operator->() const { return entry_; }
 };
 
 #endif  // KEYSTORE_BLOB_H_
diff --git a/keystore/confirmation_manager.cpp b/keystore/confirmation_manager.cpp
index 0dee4aa..3396359 100644
--- a/keystore/confirmation_manager.cpp
+++ b/keystore/confirmation_manager.cpp
@@ -184,7 +184,7 @@
     return Return<void>();
 }
 
-// Called by keystore main thread.
+// Called by keystore main thread or keymaster worker
 hidl_vec<uint8_t> ConfirmationManager::getLatestConfirmationToken() {
     lock_guard<mutex> lock(mMutex);
     return mLatestConfirmationToken;
diff --git a/keystore/grant_store.cpp b/keystore/grant_store.cpp
index 9244b7c..9e627ce 100644
--- a/keystore/grant_store.cpp
+++ b/keystore/grant_store.cpp
@@ -16,6 +16,7 @@
 
 #include "grant_store.h"
 
+#include "blob.h"
 #include <algorithm>
 #include <sstream>
 
@@ -25,10 +26,8 @@
 static const char* kKeystoreGrantInfix = "_KEYSTOREGRANT_";
 static constexpr size_t kKeystoreGrantInfixLength = 15;
 
-Grant::Grant(const std::string& alias, const std::string& owner_dir_name, const uid_t owner_uid,
-             const uint64_t grant_no)
-        : alias_(alias), owner_dir_name_(owner_dir_name), owner_uid_(owner_uid),
-          grant_no_(grant_no) {}
+Grant::Grant(const KeyBlobEntry& entry, const uint64_t grant_no)
+    : entry_(entry), grant_no_(grant_no) {}
 
 static std::pair<uint64_t, std::string> parseGrantAlias(const std::string& grantAlias) {
     auto pos = grantAlias.rfind(kKeystoreGrantInfix);
@@ -41,45 +40,45 @@
     return {grant_no, wrapped_alias};
 }
 
-std::string GrantStore::put(const uid_t uid, const std::string& alias,
-                            const std::string& owner_dir_name, const uid_t owner_uid) {
+std::string GrantStore::put(const uid_t uid, const LockedKeyBlobEntry& lockedEntry) {
+    std::unique_lock<std::shared_mutex> lock(mutex_);
     std::stringstream s;
-    s << alias << kKeystoreGrantInfix;
-    auto& uid_grant_list = grants_[uid];
+    KeyBlobEntry blobEntry = *lockedEntry;
+    s << blobEntry.alias() << kKeystoreGrantInfix;
+
+    std::set<Grant, std::less<>>& uid_grant_list = grants_[uid];
 
     bool success = false;
-    auto iterator = std::find_if(uid_grant_list.begin(), uid_grant_list.end(),
-            [&](auto& entry) {
-                return success = entry.alias_ == alias && entry.owner_dir_name_ == owner_dir_name
-                        && entry.owner_uid_ == owner_uid;
-            });
+    auto iterator =
+        std::find_if(uid_grant_list.begin(), uid_grant_list.end(),
+                     [&](const Grant& entry) { return success = entry.entry_ == blobEntry; });
     while (!success) {
-        std::tie(iterator, success) = uid_grant_list.emplace(alias, owner_dir_name, owner_uid,
-                                                             std::rand());
+        std::tie(iterator, success) = uid_grant_list.emplace(blobEntry, std::rand());
     }
     s << iterator->grant_no_;
     return s.str();
 }
 
-const Grant* GrantStore::get(const uid_t uid, const std::string& alias) const {
+ReadLockedGrant GrantStore::get(const uid_t uid, const std::string& alias) const {
+    std::shared_lock<std::shared_mutex> lock(mutex_);
     uint64_t grant_no;
     std::string wrappedAlias;
     std::tie(grant_no, wrappedAlias) = parseGrantAlias(alias);
-    if (grant_no == kInvalidGrantNo) return nullptr;
+    if (grant_no == kInvalidGrantNo) return {};
     auto uid_set_iter = grants_.find(uid);
-    if (uid_set_iter == grants_.end()) return nullptr;
+    if (uid_set_iter == grants_.end()) return {};
     auto& uid_grant_list = uid_set_iter->second;
     auto grant = uid_grant_list.find(grant_no);
-    if (grant == uid_grant_list.end()) return nullptr;
-    if (grant->alias_ != wrappedAlias) return nullptr;
-    return &(*grant);
+    if (grant == uid_grant_list.end()) return {};
+    if (grant->entry_.alias() != wrappedAlias) return {};
+    return {&(*grant), std::move(lock)};
 }
 
-bool GrantStore::removeByFileAlias(const uid_t granteeUid, const uid_t granterUid,
-        const std::string& alias) {
+bool GrantStore::removeByFileAlias(const uid_t granteeUid, const LockedKeyBlobEntry& lockedEntry) {
+    std::unique_lock<std::shared_mutex> lock(mutex_);
     auto& uid_grant_list = grants_[granteeUid];
     for (auto i = uid_grant_list.begin(); i != uid_grant_list.end(); ++i) {
-        if (i->alias_ == alias && i->owner_uid_ == granterUid) {
+        if (i->entry_ == *lockedEntry) {
             uid_grant_list.erase(i);
             return true;
         }
@@ -88,9 +87,10 @@
 }
 
 void GrantStore::removeAllGrantsToKey(const uid_t granterUid, const std::string& alias) {
+    std::unique_lock<std::shared_mutex> lock(mutex_);
     for (auto& uid_grant_list : grants_) {
         for (auto i = uid_grant_list.second.begin(); i != uid_grant_list.second.end(); ++i) {
-            if (i->alias_ == alias && i->owner_uid_ == granterUid) {
+            if (i->entry_.alias() == alias && i->entry_.uid() == granterUid) {
                 uid_grant_list.second.erase(i);
                 break;
             }
@@ -99,6 +99,7 @@
 }
 
 void GrantStore::removeAllGrantsToUid(const uid_t granteeUid) {
+    std::unique_lock<std::shared_mutex> lock(mutex_);
     grants_.erase(granteeUid);
 }
 
diff --git a/keystore/grant_store.h b/keystore/grant_store.h
index 6341c76..f8e4f91 100644
--- a/keystore/grant_store.h
+++ b/keystore/grant_store.h
@@ -17,12 +17,23 @@
 #ifndef KEYSTORE_GRANT_STORE_H_
 #define KEYSTORE_GRANT_STORE_H_
 
+#include <mutex>
 #include <set>
+#include <shared_mutex>
 #include <string>
 #include <unordered_map>
 
+#include <keystore/keystore_concurrency.h>
+
+#include "blob.h"
+
 namespace keystore {
 
+class Grant;
+
+using ReadLockedGrant =
+    ProxyLock<MutexProxyLockHelper<const Grant, std::shared_mutex, std::shared_lock>>;
+
 /**
  * Grant represents a mapping from an alias to a key file.
  * Normally, key file names are derived from the alias chosen by the client
@@ -32,16 +43,12 @@
  */
 class Grant {
 public:
-    Grant(const std::string& alias, const std::string& owner_dir_name, const uid_t owner_uid,
-          const uint64_t grant_no);
-    // the following three field are used to recover the key filename that the grant refers to
-    std::string alias_;            ///< original/wrapped key alias
-    std::string owner_dir_name_;   ///< key owner key directory
-    uid_t owner_uid_;              ///< key owner uid
+  Grant(const KeyBlobEntry& entry, const uint64_t grant_no);
+  KeyBlobEntry entry_;
 
-    uint64_t grant_no_;            ///< numeric grant identifier - randomly assigned
+  uint64_t grant_no_;  ///< numeric grant identifier - randomly assigned
 
-    operator const uint64_t&() const { return grant_no_; }
+  operator const uint64_t&() const { return grant_no_; }
 };
 
 /**
@@ -56,10 +63,9 @@
 class GrantStore {
 public:
     GrantStore() : grants_() {}
-    std::string put(const uid_t uid, const std::string& alias, const std::string& owner_dir_name,
-                    const uid_t owner_uid);
-    const Grant* get(const uid_t uid, const std::string& alias) const;
-    bool removeByFileAlias(const uid_t granteeUid, const uid_t granterUid, const std::string& alias);
+    std::string put(const uid_t uid, const LockedKeyBlobEntry& blobfile);
+    ReadLockedGrant get(const uid_t uid, const std::string& alias) const;
+    bool removeByFileAlias(const uid_t granteeUid, const LockedKeyBlobEntry& lockedEntry);
     void removeAllGrantsToKey(const uid_t granterUid, const std::string& alias);
     void removeAllGrantsToUid(const uid_t granteeUid);
 
@@ -68,6 +74,7 @@
     GrantStore& operator=(const GrantStore&) = delete;
 private:
     std::unordered_map<uid_t, std::set<Grant, std::less<>>> grants_;
+    mutable std::shared_mutex mutex_;
 };
 
 }  // namespace keystore
diff --git a/keystore/include/keystore/KeyCharacteristics.h b/keystore/include/keystore/KeyCharacteristics.h
index 7fc89c6..33c5c3a 100644
--- a/keystore/include/keystore/KeyCharacteristics.h
+++ b/keystore/include/keystore/KeyCharacteristics.h
@@ -27,6 +27,10 @@
 // Parcelable version of keystore::KeyCharacteristics
 struct KeyCharacteristics : public ::android::Parcelable {
     KeyCharacteristics(){};
+    KeyCharacteristics(keystore::KeyCharacteristics&& other) {
+        softwareEnforced = std::move(other.softwareEnforced);
+        hardwareEnforced = std::move(other.hardwareEnforced);
+    }
     explicit KeyCharacteristics(const keystore::KeyCharacteristics& other) {
         softwareEnforced = KeymasterArguments(other.softwareEnforced);
         hardwareEnforced = KeymasterArguments(other.hardwareEnforced);
diff --git a/keystore/include/keystore/KeymasterArguments.h b/keystore/include/keystore/KeymasterArguments.h
index 99074f8..fb35ee7 100644
--- a/keystore/include/keystore/KeymasterArguments.h
+++ b/keystore/include/keystore/KeymasterArguments.h
@@ -26,6 +26,7 @@
 // struct for serializing/deserializing a list of KeyParameters
 struct KeymasterArguments : public Parcelable {
     KeymasterArguments(){};
+    KeymasterArguments(hardware::hidl_vec<keystore::KeyParameter>&& other);
     explicit KeymasterArguments(const hardware::hidl_vec<keystore::KeyParameter>& other);
 
     status_t readFromParcel(const Parcel* in) override;
diff --git a/keystore/include/keystore/OperationResult.h b/keystore/include/keystore/OperationResult.h
index 2ceda9a..caa7cdb 100644
--- a/keystore/include/keystore/OperationResult.h
+++ b/keystore/include/keystore/OperationResult.h
@@ -39,6 +39,8 @@
     ::keystore::hidl_vec<::keystore::KeyParameter> outParams;
 };
 
+OperationResult operationFailed(const ::keystore::KeyStoreServiceReturnCode& error);
+
 }  // namespace keymaster
 }  // namespace security
 }  // namespace android
diff --git a/keystore/include/keystore/keystore.h b/keystore/include/keystore/keystore.h
index 07f645f..a1d4c81 100644
--- a/keystore/include/keystore/keystore.h
+++ b/keystore/include/keystore/keystore.h
@@ -27,22 +27,23 @@
 };
 
 // must be in sync with KeyStore.java,
-enum class ResponseCode: int32_t {
-    NO_ERROR          =  STATE_NO_ERROR, // 1
-    LOCKED            =  STATE_LOCKED, // 2
-    UNINITIALIZED     =  STATE_UNINITIALIZED, // 3
-    SYSTEM_ERROR      =  4,
-    PROTOCOL_ERROR    =  5,
-    PERMISSION_DENIED =  6,
-    KEY_NOT_FOUND     =  7,
-    VALUE_CORRUPTED   =  8,
-    UNDEFINED_ACTION  =  9,
-    WRONG_PASSWORD_0  = 10,
-    WRONG_PASSWORD_1  = 11,
-    WRONG_PASSWORD_2  = 12,
-    WRONG_PASSWORD_3  = 13, // MAX_RETRY = 4
+enum class ResponseCode : int32_t {
+    NO_ERROR = STATE_NO_ERROR,            // 1
+    LOCKED = STATE_LOCKED,                // 2
+    UNINITIALIZED = STATE_UNINITIALIZED,  // 3
+    SYSTEM_ERROR = 4,
+    PROTOCOL_ERROR = 5,
+    PERMISSION_DENIED = 6,
+    KEY_NOT_FOUND = 7,
+    VALUE_CORRUPTED = 8,
+    UNDEFINED_ACTION = 9,
+    WRONG_PASSWORD_0 = 10,
+    WRONG_PASSWORD_1 = 11,
+    WRONG_PASSWORD_2 = 12,
+    WRONG_PASSWORD_3 = 13,  // MAX_RETRY = 4
     SIGNATURE_INVALID = 14,
-    OP_AUTH_NEEDED    = 15, // Auth is needed for this operation before it can be used.
+    OP_AUTH_NEEDED = 15,  // Auth is needed for this operation before it can be used.
+    KEY_ALREADY_EXISTS = 16,
 };
 
 /*
diff --git a/keystore/include/keystore/keystore_concurrency.h b/keystore/include/keystore/keystore_concurrency.h
new file mode 100644
index 0000000..b60b7a6
--- /dev/null
+++ b/keystore/include/keystore/keystore_concurrency.h
@@ -0,0 +1,113 @@
+/*
+**
+** Copyright 2018, 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 KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_CONCURRENCY_H_
+#define KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_CONCURRENCY_H_
+
+#include <type_traits>
+
+namespace keystore {
+
+template <typename LockedType> class UnlockProxyLockHelper {
+  private:
+    std::function<void(LockedType*)> unlock_;
+    LockedType* value_;
+
+  public:
+    using lockedType = LockedType;
+    UnlockProxyLockHelper() : value_(nullptr) {}
+    UnlockProxyLockHelper(LockedType* value, std::function<void(LockedType*)>&& unlock)
+        : unlock_(std::move(unlock)), value_(value) {}
+    ~UnlockProxyLockHelper() {
+        if (unlock_) unlock_(value_);
+    }
+    UnlockProxyLockHelper(UnlockProxyLockHelper&& rhs)
+        : unlock_(std::move(rhs.unlock_)), value_(rhs.value_) {
+        rhs.value_ = nullptr;
+        rhs.unlock_ = {};
+    }
+    UnlockProxyLockHelper& operator=(UnlockProxyLockHelper&& rhs) {
+        if (this != &rhs) {
+            UnlockProxyLockHelper dummy(std::move(*this));
+            unlock_ = std::move(rhs.unlock_);
+            value_ = std::move(rhs.value_);
+            rhs.value_ = nullptr;
+            rhs.unlock_ = {};
+        }
+        return *this;
+    }
+    UnlockProxyLockHelper(const UnlockProxyLockHelper& rhs) = delete;
+    UnlockProxyLockHelper& operator=(const UnlockProxyLockHelper& rhs) = delete;
+
+    template <typename T = LockedType>
+    std::enable_if_t<!std::is_const<LockedType>::value, T*> value() {
+        return value_;
+    }
+    const LockedType* value() const { return value_; }
+};
+
+template <typename LockedType, typename MutexType, template <typename> class GuardType>
+class MutexProxyLockHelper {
+  private:
+    GuardType<MutexType> lock_;
+    LockedType* value_;
+
+  public:
+    using lockedType = LockedType;
+    MutexProxyLockHelper() : value_(nullptr) {}
+    MutexProxyLockHelper(LockedType* value, GuardType<MutexType>&& lock)
+        : lock_(std::move(lock)), value_(value) {}
+
+    template <typename T = LockedType>
+    std::enable_if_t<!std::is_const<LockedType>::value, T*> value() {
+        return value_;
+    }
+    const LockedType* value() const { return value_; }
+};
+
+template <typename Implementation> class ProxyLock {
+  private:
+    Implementation impl_;
+
+  public:
+    ProxyLock() : impl_() {}
+    template <typename... Args> ProxyLock(Args&&... args) : impl_{std::forward<Args>(args)...} {}
+    ProxyLock(Implementation&& impl) : impl_(std::move(impl)) {}
+    operator bool() const { return impl_.value() != nullptr; }
+
+    template <typename T = typename Implementation::lockedType>
+    std::enable_if_t<!std::is_const<typename Implementation::lockedType>::value, T*> operator->() {
+        return impl_.value();
+    }
+
+    template <typename T = typename Implementation::lockedType>
+    std::enable_if_t<!std::is_const<typename Implementation::lockedType>::value, T&> operator*() {
+        return *impl_.value();
+    }
+
+    const std::remove_const_t<typename Implementation::lockedType>* operator->() const {
+        return impl_.value();
+    }
+
+    const std::remove_const_t<typename Implementation::lockedType>& operator*() const {
+        return *impl_.value();
+    }
+};
+
+}  // namespace keystore
+
+#endif  // KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_CONCURRENCY_H_
diff --git a/keystore/key_store_service.cpp b/keystore/key_store_service.cpp
index dcf1acb..7ce58ca 100644
--- a/keystore/key_store_service.cpp
+++ b/keystore/key_store_service.cpp
@@ -23,6 +23,7 @@
 #include <sys/stat.h>
 
 #include <algorithm>
+#include <atomic>
 #include <sstream>
 
 #include <android-base/scopeguard.h>
@@ -36,6 +37,7 @@
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
+#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
 #include <android/hardware/keymaster/3.0/IHwKeymasterDevice.h>
 
 #include "defaults.h"
@@ -44,6 +46,7 @@
 #include "keystore_keymaster_enforcement.h"
 #include "keystore_utils.h"
 #include <keystore/keystore_hidl_support.h>
+#include <keystore/keystore_return_types.h>
 
 #include <hardware/hw_auth_token.h>
 
@@ -59,10 +62,10 @@
 using android::security::keymaster::KeymasterArguments;
 using android::security::keymaster::KeymasterBlob;
 using android::security::keymaster::KeymasterCertificateChain;
+using android::security::keymaster::operationFailed;
 using android::security::keymaster::OperationResult;
 using ConfirmationResponseCode = android::hardware::confirmationui::V1_0::ResponseCode;
 
-constexpr size_t kMaxOperations = 15;
 constexpr double kIdRotationPeriod = 30 * 24 * 60 * 60; /* Thirty days, in seconds */
 const char* kTimestampFilePath = "timestamp";
 const int ID_ATTESTATION_REQUEST_GENERIC_INFO = 1 << 0;
@@ -74,12 +77,9 @@
 typedef std::unique_ptr<BIGNUM, BIGNUM_Delete> Unique_BIGNUM;
 
 bool containsTag(const hidl_vec<KeyParameter>& params, Tag tag) {
-    return params.end() != std::find_if(params.begin(), params.end(),
-                                        [&](auto& param) { return param.tag == tag; });
-}
-
-bool isAuthenticationBound(const hidl_vec<KeyParameter>& params) {
-    return !containsTag(params, Tag::NO_AUTH_REQUIRED);
+    return params.end() !=
+           std::find_if(params.begin(), params.end(),
+                        [&](const KeyParameter& param) { return param.tag == tag; });
 }
 
 std::pair<KeyStoreServiceReturnCode, bool> hadFactoryResetSinceIdRotation() {
@@ -143,15 +143,6 @@
 
 }  // anonymous namespace
 
-void KeyStoreService::binderDied(const wp<IBinder>& who) {
-    auto operations = mOperationMap.getOperationsForToken(who.unsafe_get());
-    for (const auto& token : operations) {
-        int32_t unused_result;
-        abort(token, &unused_result);
-    }
-    mConfirmationManager->binderDied(who);
-}
-
 Status KeyStoreService::getState(int32_t userId, int32_t* aidl_return) {
     if (!checkBinderPermission(P_GET_STATE)) {
         *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED);
@@ -170,10 +161,14 @@
     }
 
     String8 name8(name);
+    ResponseCode rc;
     Blob keyBlob;
-    KeyStoreServiceReturnCode rc =
-        mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_GENERIC);
-    if (!rc.isOk()) {
+    Blob charBlob;
+    LockedKeyBlobEntry lockedEntry;
+
+    std::tie(rc, keyBlob, charBlob, lockedEntry) =
+        mKeyStore->getKeyForName(name8, targetUid, TYPE_GENERIC);
+    if (rc != ResponseCode::NO_ERROR) {
         *item = ::std::vector<uint8_t>();
         // Return empty array if key is not found
         // TODO: consider having returned value nullable or parse exception on the client.
@@ -196,13 +191,18 @@
     }
 
     String8 name8(name);
-    String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid, ::TYPE_GENERIC));
+    auto lockedEntry = mKeyStore->getLockedBlobEntryIfNotExists(name8.string(), targetUid);
+
+    if (!lockedEntry) {
+        ALOGE("failed to grab lock on blob entry %u_%s", targetUid, name8.string());
+        *aidl_return = static_cast<int32_t>(ResponseCode::KEY_ALREADY_EXISTS);
+        return Status::ok();
+    }
 
     Blob keyBlob(&item[0], item.size(), nullptr, 0, ::TYPE_GENERIC);
     keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
 
-    *aidl_return =
-        static_cast<int32_t>(mKeyStore->put(filename.string(), &keyBlob, get_user_id(targetUid)));
+    *aidl_return = static_cast<int32_t>(mKeyStore->put(lockedEntry, keyBlob, {}));
     return Status::ok();
 }
 
@@ -214,26 +214,15 @@
     }
     String8 name8(name);
     ALOGI("del %s %d", name8.string(), targetUid);
-    auto filename = mKeyStore->getBlobFileNameIfExists(name8, targetUid, ::TYPE_ANY);
-    if (!filename.isOk()) {
+    auto lockedEntry = mKeyStore->getLockedBlobEntryIfExists(name8.string(), targetUid);
+    if (!lockedEntry) {
         *aidl_return = static_cast<int32_t>(ResponseCode::KEY_NOT_FOUND);
         return Status::ok();
     }
 
-    ResponseCode result =
-        mKeyStore->del(filename.value().string(), ::TYPE_ANY, get_user_id(targetUid));
-    if (result != ResponseCode::NO_ERROR) {
-        *aidl_return = static_cast<int32_t>(result);
-        return Status::ok();
-    }
+    ResponseCode result = mKeyStore->del(lockedEntry);
 
-    filename = mKeyStore->getBlobFileNameIfExists(name8, targetUid, ::TYPE_KEY_CHARACTERISTICS);
-    if (filename.isOk()) {
-        *aidl_return = static_cast<int32_t>(mKeyStore->del(
-            filename.value().string(), ::TYPE_KEY_CHARACTERISTICS, get_user_id(targetUid)));
-        return Status::ok();
-    }
-    *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR);
+    *aidl_return = static_cast<int32_t>(result);
     return Status::ok();
 }
 
@@ -244,13 +233,14 @@
         return Status::ok();
     }
 
-    auto filename = mKeyStore->getBlobFileNameIfExists(String8(name), targetUid, ::TYPE_ANY);
-    *aidl_return = static_cast<int32_t>(filename.isOk() ? ResponseCode::NO_ERROR
-                                                        : ResponseCode::KEY_NOT_FOUND);
+    LockedKeyBlobEntry lockedEntry =
+        mKeyStore->getLockedBlobEntryIfExists(String8(name).string(), targetUid);
+    *aidl_return =
+        static_cast<int32_t>(lockedEntry ? ResponseCode::NO_ERROR : ResponseCode::KEY_NOT_FOUND);
     return Status::ok();
 }
 
-Status KeyStoreService::list(const String16& prefix, int targetUid,
+Status KeyStoreService::list(const String16& prefix, int32_t targetUid,
                              ::std::vector<::android::String16>* matches) {
     targetUid = getEffectiveUid(targetUid);
     if (!checkBinderPermission(P_LIST, targetUid)) {
@@ -258,15 +248,26 @@
             static_cast<int32_t>(ResponseCode::PERMISSION_DENIED));
     }
     const String8 prefix8(prefix);
-    String8 filename(mKeyStore->getKeyNameForUid(prefix8, targetUid, TYPE_ANY));
-    android::Vector<android::String16> matches_internal;
-    if (mKeyStore->list(filename, &matches_internal, get_user_id(targetUid)) !=
-        ResponseCode::NO_ERROR) {
-        return Status::fromServiceSpecificError(static_cast<int32_t>(ResponseCode::SYSTEM_ERROR));
+    const std::string stdPrefix(prefix8.string());
+
+    ResponseCode rc;
+    std::list<LockedKeyBlobEntry> internal_matches;
+
+    std::tie(rc, internal_matches) = LockedKeyBlobEntry::list(
+        mKeyStore->getUserStateDB().getUserStateByUid(targetUid)->getUserDirName(),
+        [&](uid_t uid, const std::string& alias) {
+            std::mismatch(stdPrefix.begin(), stdPrefix.end(), alias.begin(), alias.end());
+            return uid == static_cast<uid_t>(targetUid) &&
+                   std::mismatch(stdPrefix.begin(), stdPrefix.end(), alias.begin(), alias.end())
+                           .first == stdPrefix.end();
+        });
+
+    if (rc != ResponseCode::NO_ERROR) {
+        return Status::fromServiceSpecificError(static_cast<int32_t>(rc));
     }
-    matches->clear();
-    for (size_t i = 0; i < matches_internal.size(); ++i) {
-        matches->push_back(matches_internal[i]);
+
+    for (LockedKeyBlobEntry& entry : internal_matches) {
+        matches->push_back(String16(entry->alias().substr(prefix8.size()).c_str()));
     }
     return Status::ok();
 }
@@ -293,7 +294,7 @@
     const String8 password8(password);
     // Flush the auth token table to prevent stale tokens from sticking
     // around.
-    mAuthTokenTable.Clear();
+    mKeyStore->getAuthTokenTable().Clear();
 
     if (password.size() == 0) {
         ALOGI("Secure lockscreen for user %d removed, deleting encrypted entries", userId);
@@ -374,7 +375,7 @@
         return Status::ok();
     }
 
-    enforcement_policy.set_device_locked(true, userId);
+    mKeyStore->getEnforcementPolicy().set_device_locked(true, userId);
     mKeyStore->lock(userId);
     *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR);
     return Status::ok();
@@ -403,7 +404,7 @@
         return Status::ok();
     }
 
-    enforcement_policy.set_device_locked(false, userId);
+    mKeyStore->getEnforcementPolicy().set_device_locked(false, userId);
     const String8 password8(pw);
     // read master key, decrypt with password, initialize mMasterKey*.
     *aidl_return = static_cast<int32_t>(mKeyStore->readMasterKey(password8, userId));
@@ -431,15 +432,13 @@
     }
 
     String8 name8(name);
-    String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, callingUid, ::TYPE_ANY));
-
-    if (access(filename.string(), R_OK) == -1) {
+    auto lockedEntry = mKeyStore->getLockedBlobEntryIfExists(name8.string(), callingUid);
+    if (!lockedEntry) {
         *aidl_return = String16();
         return Status::ok();
     }
 
-    *aidl_return =
-        String16(mKeyStore->addGrant(String8(name).string(), callingUid, granteeUid).c_str());
+    *aidl_return = String16(mKeyStore->addGrant(lockedEntry, granteeUid).c_str());
     return Status::ok();
 }
 
@@ -453,17 +452,13 @@
     }
 
     String8 name8(name);
-    String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, callingUid, ::TYPE_ANY));
 
-    if (access(filename.string(), R_OK) == -1) {
-        *aidl_return = static_cast<int32_t>((errno != ENOENT) ? ResponseCode::SYSTEM_ERROR
-                                                              : ResponseCode::KEY_NOT_FOUND);
-        return Status::ok();
+    auto lockedEntry = mKeyStore->getLockedBlobEntryIfExists(name8.string(), callingUid);
+    if (!lockedEntry) {
+        *aidl_return = static_cast<int32_t>(ResponseCode::KEY_NOT_FOUND);
     }
 
-    *aidl_return = static_cast<int32_t>(mKeyStore->removeGrant(name8, callingUid, granteeUid)
-                                            ? ResponseCode::NO_ERROR
-                                            : ResponseCode::KEY_NOT_FOUND);
+    *aidl_return = mKeyStore->removeGrant(lockedEntry, granteeUid);
     return Status::ok();
 }
 
@@ -474,18 +469,20 @@
         *time = -1L;
         return Status::ok();
     }
+    String8 name8(name);
 
-    auto filename = mKeyStore->getBlobFileNameIfExists(String8(name), targetUid, ::TYPE_ANY);
-
-    if (!filename.isOk()) {
-        ALOGW("could not access %s for getmtime", filename.value().string());
+    auto lockedEntry = mKeyStore->getLockedBlobEntryIfExists(name8.string(), targetUid);
+    if (!lockedEntry) {
+        ALOGW("could not access key with alias %s for getmtime", name8.string());
         *time = -1L;
         return Status::ok();
     }
 
-    int fd = TEMP_FAILURE_RETRY(open(filename.value().string(), O_NOFOLLOW, O_RDONLY));
+    std::string filename = lockedEntry->getKeyBlobPath();
+
+    int fd = TEMP_FAILURE_RETRY(open(filename.c_str(), O_NOFOLLOW, O_RDONLY));
     if (fd < 0) {
-        ALOGW("could not open %s for getmtime", filename.value().string());
+        ALOGW("could not open %s for getmtime", filename.c_str());
         *time = -1L;
         return Status::ok();
     }
@@ -494,7 +491,7 @@
     int ret = fstat(fd, &s);
     close(fd);
     if (ret == -1) {
-        ALOGW("could not stat %s for getmtime", filename.value().string());
+        ALOGW("could not stat %s for getmtime", filename.c_str());
         *time = -1L;
         return Status::ok();
     }
@@ -518,33 +515,31 @@
 
     mKeyStore->removeAllGrantsToUid(targetUid);
 
-    String8 prefix = String8::format("%u_", targetUid);
-    Vector<String16> aliases;
-    if (mKeyStore->list(prefix, &aliases, get_user_id(targetUid)) != ResponseCode::NO_ERROR) {
-        *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
+    ResponseCode rc;
+    std::list<LockedKeyBlobEntry> entries;
+
+    // list has a fence making sure no workers are modifying blob files before iterating the
+    // data base. All returned entries are locked.
+    std::tie(rc, entries) = LockedKeyBlobEntry::list(
+        mKeyStore->getUserStateDB().getUserStateByUid(targetUid)->getUserDirName(),
+        [&](uid_t uid, const std::string&) -> bool { return uid == targetUid; });
+
+    if (rc != ResponseCode::NO_ERROR) {
+        *aidl_return = static_cast<int32_t>(rc);
         return Status::ok();
     }
 
-    for (uint32_t i = 0; i < aliases.size(); i++) {
-        String8 name8(aliases[i]);
-        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid, ::TYPE_ANY));
-
+    for (LockedKeyBlobEntry& lockedEntry : entries) {
         if (get_app_id(targetUid) == AID_SYSTEM) {
             Blob keyBlob;
-            ResponseCode responseCode =
-                mKeyStore->get(filename.string(), &keyBlob, ::TYPE_ANY, get_user_id(targetUid));
-            if (responseCode == ResponseCode::NO_ERROR && keyBlob.isCriticalToDeviceEncryption()) {
+            Blob charBlob;
+            std::tie(rc, keyBlob, charBlob) = mKeyStore->get(lockedEntry);
+            if (rc == ResponseCode::NO_ERROR && keyBlob.isCriticalToDeviceEncryption()) {
                 // Do not clear keys critical to device encryption under system uid.
                 continue;
             }
         }
-
-        mKeyStore->del(filename.string(), ::TYPE_ANY, get_user_id(targetUid));
-
-        // del() will fail silently if no cached characteristics are present for this alias.
-        String8 chr_filename(
-            mKeyStore->getKeyNameForUidWithDir(name8, targetUid, ::TYPE_KEY_CHARACTERISTICS));
-        mKeyStore->del(chr_filename.string(), ::TYPE_KEY_CHARACTERISTICS, get_user_id(targetUid));
+        mKeyStore->del(lockedEntry);
     }
     *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR);
     return Status::ok();
@@ -555,10 +550,15 @@
     auto device = mKeyStore->getDevice(flagsToSecurityLevel(flags));
     if (!device) {
         *aidl_return = static_cast<int32_t>(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
-    } else {
-        *aidl_return = static_cast<int32_t>(
-            KeyStoreServiceReturnCode(KS_HANDLE_HIDL_ERROR(device->addRngEntropy(entropy))));
+        return Status::ok();
     }
+    std::promise<KeyStoreServiceReturnCode> resultPromise;
+    auto resultFuture = resultPromise.get_future();
+
+    device->addRngEntropy(
+        entropy, [&](Return<ErrorCode> rc) { resultPromise.set_value(KS_HANDLE_HIDL_ERROR(rc)); });
+    resultFuture.wait();
+    *aidl_return = int32_t(resultFuture.get());
     return Status::ok();
 }
 
@@ -604,105 +604,34 @@
         *aidl_return = static_cast<int32_t>(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
         return Status::ok();
     }
-    AuthorizationSet keyCharacteristics = params.getParameters();
 
-    // TODO: Seed from Linux RNG before this.
-    rc = KS_HANDLE_HIDL_ERROR(dev->addRngEntropy(entropy));
-    if (!rc.isOk()) {
-        *aidl_return = static_cast<int32_t>(rc);
-        return Status::ok();
-    }
-
-    KeyStoreServiceReturnCode error;
-    auto hidl_cb = [&](ErrorCode ret, const ::std::vector<uint8_t>& hidlKeyBlob,
-                       const KeyCharacteristics& keyCharacteristics) {
-        error = ret;
-        if (!error.isOk()) {
-            return;
-        }
-        if (outCharacteristics)
-            *outCharacteristics =
-                ::android::security::keymaster::KeyCharacteristics(keyCharacteristics);
-
-        // Write the key
-        String8 name8(name);
-        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, uid, ::TYPE_KEYMASTER_10));
-
-        Blob keyBlob(&hidlKeyBlob[0], hidlKeyBlob.size(), nullptr, 0, ::TYPE_KEYMASTER_10);
-        keyBlob.setSecurityLevel(securityLevel);
-        keyBlob.setCriticalToDeviceEncryption(flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
-        if (isAuthenticationBound(params.getParameters()) &&
-            !keyBlob.isCriticalToDeviceEncryption()) {
-            keyBlob.setSuperEncrypted(true);
-        }
-        keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
-
-        error = mKeyStore->put(filename.string(), &keyBlob, get_user_id(uid));
-    };
-
-    rc = KS_HANDLE_HIDL_ERROR(dev->generateKey(params.getParameters(), hidl_cb));
-    if (!rc.isOk()) {
-        *aidl_return = static_cast<int32_t>(rc);
-        return Status::ok();
-    }
-    if (!error.isOk()) {
-        ALOGE("Failed to generate key -> falling back to software keymaster");
-        uploadKeyCharacteristicsAsProto(params.getParameters(), false /* wasCreationSuccessful */);
-        securityLevel = SecurityLevel::SOFTWARE;
-
-        // No fall back for 3DES
-        for (auto& param : params.getParameters()) {
-            auto algorithm = authorizationValue(TAG_ALGORITHM, param);
-            if (algorithm.isOk() && algorithm.value() == Algorithm::TRIPLE_DES) {
-                *aidl_return = static_cast<int32_t>(ErrorCode::UNSUPPORTED_ALGORITHM);
-                return Status::ok();
-            }
-        }
-
-        auto fallback = mKeyStore->getFallbackDevice();
-        if (!fallback) {
-            *aidl_return = static_cast<int32_t>(error);
-            return Status::ok();
-        }
-        rc = KS_HANDLE_HIDL_ERROR(fallback->generateKey(params.getParameters(), hidl_cb));
-        if (!rc.isOk()) {
-            *aidl_return = static_cast<int32_t>(rc);
-            return Status::ok();
-        }
-        if (!error.isOk()) {
-            *aidl_return = static_cast<int32_t>(error);
-            return Status::ok();
-        }
-    } else {
-        uploadKeyCharacteristicsAsProto(params.getParameters(), true /* wasCreationSuccessful */);
-    }
-
-    if (!containsTag(params.getParameters(), Tag::USER_ID)) {
-        // Most Java processes don't have access to this tag
-        KeyParameter user_id;
-        user_id.tag = Tag::USER_ID;
-        user_id.f.integer = multiuser_get_user_id(uid);
-        keyCharacteristics.push_back(user_id);
-    }
-
-    // Write the characteristics:
     String8 name8(name);
-    String8 cFilename(mKeyStore->getKeyNameForUidWithDir(name8, uid, ::TYPE_KEY_CHARACTERISTICS));
-
-    std::stringstream kc_stream;
-    keyCharacteristics.Serialize(&kc_stream);
-    if (kc_stream.bad()) {
-        *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
+    auto lockedEntry = mKeyStore->getLockedBlobEntryIfNotExists(name8.string(), uid);
+    if (!lockedEntry) {
+        *aidl_return = static_cast<int32_t>(ResponseCode::KEY_ALREADY_EXISTS);
         return Status::ok();
     }
-    auto kc_buf = kc_stream.str();
-    Blob charBlob(reinterpret_cast<const uint8_t*>(kc_buf.data()), kc_buf.size(), nullptr, 0,
-                  ::TYPE_KEY_CHARACTERISTICS);
-    charBlob.setSecurityLevel(securityLevel);
-    charBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
 
-    *aidl_return =
-        static_cast<int32_t>(mKeyStore->put(cFilename.string(), &charBlob, get_user_id(uid)));
+    logOnScopeExit.Disable();
+
+    std::promise<KeyStoreServiceReturnCode> resultPromise;
+    auto resultFuture = resultPromise.get_future();
+
+    dev->generateKey(std::move(lockedEntry), params.getParameters(), entropy, flags,
+                     [&, uid](KeyStoreServiceReturnCode rc, KeyCharacteristics keyCharacteristics) {
+                         if (outCharacteristics && rc.isOk()) {
+                             *outCharacteristics = android::security::keymaster::KeyCharacteristics(
+                                 keyCharacteristics);
+                         }
+                         if (__android_log_security()) {
+                             android_log_event_list(SEC_TAG_AUTH_KEY_GENERATED)
+                                 << rc.isOk() << String8(name) << int32_t(uid) << LOG_ID_SECURITY;
+                         }
+                         resultPromise.set_value(rc);
+                     });
+
+    resultFuture.wait();
+    *aidl_return = int32_t(resultFuture.get());
     return Status::ok();
 }
 
@@ -725,87 +654,45 @@
         return Status::ok();
     }
 
-    Blob keyBlob;
     String8 name8(name);
 
-    KeyStoreServiceReturnCode rc =
-        mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_KEYMASTER_10);
-    if (rc == ResponseCode::UNINITIALIZED) {
-        /*
-         * If we fail reading the blob because the master key is missing we try to retrieve the
-         * key characteristics from the characteristics file. This happens when auth-bound
-         * keys are used after a screen lock has been removed by the user.
-         */
-        rc = mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_KEY_CHARACTERISTICS);
-        if (!rc.isOk()) {
-            *aidl_return = static_cast<int32_t>(rc);
-            return Status::ok();
-        }
-        AuthorizationSet keyCharacteristics;
-        // TODO write one shot stream buffer to avoid copying (twice here)
-        std::string charBuffer(reinterpret_cast<const char*>(keyBlob.getValue()),
-                               keyBlob.getLength());
-        std::stringstream charStream(charBuffer);
-        keyCharacteristics.Deserialize(&charStream);
+    ResponseCode rc;
+    Blob keyBlob;
+    Blob charBlob;
+    LockedKeyBlobEntry lockedEntry;
 
-        outCharacteristics->softwareEnforced = KeymasterArguments(keyCharacteristics.hidl_data());
-        *aidl_return = static_cast<int32_t>(rc);
-        return Status::ok();
-    } else if (!rc.isOk()) {
+    std::tie(rc, keyBlob, charBlob, lockedEntry) =
+        mKeyStore->getKeyForName(name8, targetUid, TYPE_KEYMASTER_10);
+
+    if (rc != ResponseCode::NO_ERROR) {
         *aidl_return = static_cast<int32_t>(rc);
         return Status::ok();
     }
 
-    auto hidlKeyBlob = blob2hidlVec(keyBlob);
     auto dev = mKeyStore->getDevice(keyBlob);
-
-    KeyStoreServiceReturnCode error;
-
-    auto hidlCb = [&](ErrorCode ret, const KeyCharacteristics& keyCharacteristics) {
-        error = ret;
-        if (!error.isOk()) {
-            if (error == ErrorCode::INVALID_KEY_BLOB) {
-                log_key_integrity_violation(name8, targetUid);
-            }
-            return;
-        }
-        *outCharacteristics =
-            ::android::security::keymaster::KeyCharacteristics(keyCharacteristics);
-    };
-
-    rc = KS_HANDLE_HIDL_ERROR(
-        dev->getKeyCharacteristics(hidlKeyBlob, clientId.getData(), appData.getData(), hidlCb));
-    if (!rc.isOk()) {
-        *aidl_return = static_cast<int32_t>(rc);
+    if (!dev) {
+        *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
         return Status::ok();
     }
 
-    if (error == ErrorCode::KEY_REQUIRES_UPGRADE) {
-        AuthorizationSet upgradeParams;
-        if (clientId.getData().size()) {
-            upgradeParams.push_back(TAG_APPLICATION_ID, clientId.getData());
-        }
-        if (appData.getData().size()) {
-            upgradeParams.push_back(TAG_APPLICATION_DATA, appData.getData());
-        }
-        rc = upgradeKeyBlob(name, targetUid, upgradeParams, &keyBlob);
-        if (!rc.isOk()) {
-            *aidl_return = static_cast<int32_t>(rc);
-            return Status::ok();
-        }
+    // If the charBlob is up to date, it simply moves the argument blobs to the returned blobs
+    // and extracts the characteristics on the way. Otherwise it updates the cache file with data
+    // from keymaster. It may also upgrade the key blob.
+    std::promise<KeyStoreServiceReturnCode> resultPromise;
+    auto resultFuture = resultPromise.get_future();
 
-        auto upgradedHidlKeyBlob = blob2hidlVec(keyBlob);
+    dev->getKeyCharacteristics(
+        std::move(lockedEntry), clientId.getData(), appData.getData(), std::move(keyBlob),
+        std::move(charBlob),
+        [&](KeyStoreServiceReturnCode rc, KeyCharacteristics keyCharacteristics) {
+            if (outCharacteristics && rc.isOk()) {
+                *outCharacteristics = std::move(keyCharacteristics);
+            }
+            resultPromise.set_value(rc);
+        });
 
-        rc = KS_HANDLE_HIDL_ERROR(dev->getKeyCharacteristics(
-            upgradedHidlKeyBlob, clientId.getData(), appData.getData(), hidlCb));
-        if (!rc.isOk()) {
-            *aidl_return = static_cast<int32_t>(rc);
-            return Status::ok();
-        }
-        // Note that, on success, "error" will have been updated by the hidlCB callback.
-        // So it is fine to return "error" below.
-    }
-    *aidl_return = static_cast<int32_t>(KeyStoreServiceReturnCode(error));
+    resultFuture.wait();
+    *aidl_return = int32_t(resultFuture.get());
     return Status::ok();
 }
 
@@ -825,6 +712,7 @@
     KeyStoreServiceReturnCode rc =
         checkBinderPermissionAndKeystoreState(P_INSERT, uid, flags & KEYSTORE_FLAG_ENCRYPTED);
     if (!rc.isOk()) {
+        LOG(ERROR) << "permissission denied";
         *aidl_return = static_cast<int32_t>(rc);
         return Status::ok();
     }
@@ -837,110 +725,40 @@
     SecurityLevel securityLevel = flagsToSecurityLevel(flags);
     auto dev = mKeyStore->getDevice(securityLevel);
     if (!dev) {
+        LOG(ERROR) << "importKey - cound not get keymaster device";
         *aidl_return = static_cast<int32_t>(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
         return Status::ok();
     }
 
     String8 name8(name);
-
-    KeyStoreServiceReturnCode error;
-
-    auto hidlCb = [&](ErrorCode ret, const ::std::vector<uint8_t>& keyBlob,
-                      const KeyCharacteristics& keyCharacteristics) {
-        error = ret;
-        if (!error.isOk()) {
-            return;
-        }
-        if (outCharacteristics)
-            *outCharacteristics =
-                ::android::security::keymaster::KeyCharacteristics(keyCharacteristics);
-
-        // Write the key:
-        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, uid, ::TYPE_KEYMASTER_10));
-
-        Blob ksBlob(&keyBlob[0], keyBlob.size(), nullptr, 0, ::TYPE_KEYMASTER_10);
-        ksBlob.setSecurityLevel(securityLevel);
-        ksBlob.setCriticalToDeviceEncryption(flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
-        if (isAuthenticationBound(params.getParameters()) &&
-            !ksBlob.isCriticalToDeviceEncryption()) {
-            ksBlob.setSuperEncrypted(true);
-        }
-        ksBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
-
-        error = mKeyStore->put(filename.string(), &ksBlob, get_user_id(uid));
-    };
-
-    rc = KS_HANDLE_HIDL_ERROR(
-        dev->importKey(params.getParameters(), KeyFormat(format), keyData, hidlCb));
-    // possible hidl error
-    if (!rc.isOk()) {
-        *aidl_return = static_cast<int32_t>(rc);
+    auto lockedEntry = mKeyStore->getLockedBlobEntryIfNotExists(name8.string(), uid);
+    if (!lockedEntry) {
+        LOG(ERROR) << "importKey - key: " << name8.string() << " " << int(uid)
+                   << " already exists.";
+        *aidl_return = static_cast<int32_t>(ResponseCode::KEY_ALREADY_EXISTS);
         return Status::ok();
     }
-    // now check error from callback
-    if (!error.isOk()) {
-        ALOGE("Failed to import key -> falling back to software keymaster");
-        uploadKeyCharacteristicsAsProto(params.getParameters(), false /* wasCreationSuccessful */);
-        securityLevel = SecurityLevel::SOFTWARE;
 
-        // No fall back for 3DES
-        for (auto& param : params.getParameters()) {
-            auto algorithm = authorizationValue(TAG_ALGORITHM, param);
-            if (algorithm.isOk() && algorithm.value() == Algorithm::TRIPLE_DES) {
-                *aidl_return = static_cast<int32_t>(ErrorCode::UNSUPPORTED_ALGORITHM);
-                return Status::ok();
-            }
-        }
+    logOnScopeExit.Disable();
 
-        auto fallback = mKeyStore->getFallbackDevice();
-        if (!fallback) {
-            *aidl_return = static_cast<int32_t>(error);
-            return Status::ok();
-        }
-        rc = KS_HANDLE_HIDL_ERROR(
-            fallback->importKey(params.getParameters(), KeyFormat(format), keyData, hidlCb));
-        // possible hidl error
-        if (!rc.isOk()) {
-            *aidl_return = static_cast<int32_t>(rc);
-            return Status::ok();
-        }
-        // now check error from callback
-        if (!error.isOk()) {
-            *aidl_return = static_cast<int32_t>(error);
-            return Status::ok();
-        }
-    } else {
-        uploadKeyCharacteristicsAsProto(params.getParameters(), true /* wasCreationSuccessful */);
-    }
+    std::promise<KeyStoreServiceReturnCode> resultPromise;
+    auto resultFuture = resultPromise.get_future();
 
-    // Write the characteristics:
-    String8 cFilename(mKeyStore->getKeyNameForUidWithDir(name8, uid, ::TYPE_KEY_CHARACTERISTICS));
+    dev->importKey(std::move(lockedEntry), params.getParameters(), KeyFormat(format), keyData,
+                   flags,
+                   [&, uid](KeyStoreServiceReturnCode rc, KeyCharacteristics keyCharacteristics) {
+                       if (outCharacteristics && rc.isOk()) {
+                           *outCharacteristics = std::move(keyCharacteristics);
+                       }
+                       if (__android_log_security()) {
+                           android_log_event_list(SEC_TAG_KEY_IMPORTED)
+                               << rc.isOk() << String8(name) << int32_t(uid) << LOG_ID_SECURITY;
+                       }
+                       resultPromise.set_value(rc);
+                   });
 
-    AuthorizationSet opParams = params.getParameters();
-    if (!containsTag(params.getParameters(), Tag::USER_ID)) {
-        // Most Java processes don't have access to this tag
-        KeyParameter user_id;
-        user_id.tag = Tag::USER_ID;
-        user_id.f.integer = multiuser_get_user_id(uid);
-        opParams.push_back(user_id);
-    }
-
-    std::stringstream kcStream;
-    opParams.Serialize(&kcStream);
-    if (kcStream.bad()) {
-        *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
-        return Status::ok();
-    }
-    auto kcBuf = kcStream.str();
-
-    Blob charBlob(reinterpret_cast<const uint8_t*>(kcBuf.data()), kcBuf.size(), nullptr, 0,
-                  ::TYPE_KEY_CHARACTERISTICS);
-    charBlob.setSecurityLevel(securityLevel);
-    charBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
-
-    *aidl_return =
-        static_cast<int32_t>(mKeyStore->put(cFilename.string(), &charBlob, get_user_id(uid)));
-
+    resultFuture.wait();
+    *aidl_return = int32_t(resultFuture.get());
     return Status::ok();
 }
 
@@ -957,56 +775,31 @@
         return Status::ok();
     }
 
-    Blob keyBlob;
     String8 name8(name);
 
-    result->resultCode = mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_KEYMASTER_10);
-    if (!result->resultCode.isOk()) {
+    KeyStoreServiceReturnCode rc;
+    Blob keyBlob;
+    Blob charBlob;
+    LockedKeyBlobEntry lockedEntry;
+
+    std::tie(rc, keyBlob, charBlob, lockedEntry) =
+        mKeyStore->getKeyForName(name8, targetUid, TYPE_KEYMASTER_10);
+    if (!rc) {
+        result->resultCode = rc;
         return Status::ok();
     }
 
-    auto key = blob2hidlVec(keyBlob);
     auto dev = mKeyStore->getDevice(keyBlob);
+    std::promise<void> resultPromise;
+    auto resultFuture = resultPromise.get_future();
 
-    auto hidlCb = [&](ErrorCode ret, const ::android::hardware::hidl_vec<uint8_t>& keyMaterial) {
-        result->resultCode = ret;
-        if (!result->resultCode.isOk()) {
-            if (result->resultCode == ErrorCode::INVALID_KEY_BLOB) {
-                log_key_integrity_violation(name8, targetUid);
-            }
-            return;
-        }
-        result->exportData = keyMaterial;
-    };
-    KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(
-        dev->exportKey(KeyFormat(format), key, clientId.getData(), appData.getData(), hidlCb));
-    // Overwrite result->resultCode only on HIDL error. Otherwise we want the result set in the
-    // callback hidlCb.
-    if (!rc.isOk()) {
-        result->resultCode = rc;
-    }
+    dev->exportKey(std::move(lockedEntry), KeyFormat(format), clientId.getData(), appData.getData(),
+                   std::move(keyBlob), std::move(charBlob), [&](ExportResult exportResult) {
+                       *result = std::move(exportResult);
+                       resultPromise.set_value();
+                   });
 
-    if (result->resultCode == ErrorCode::KEY_REQUIRES_UPGRADE) {
-        AuthorizationSet upgradeParams;
-        if (clientId.getData().size()) {
-            upgradeParams.push_back(TAG_APPLICATION_ID, clientId.getData());
-        }
-        if (appData.getData().size()) {
-            upgradeParams.push_back(TAG_APPLICATION_DATA, appData.getData());
-        }
-        result->resultCode = upgradeKeyBlob(name, targetUid, upgradeParams, &keyBlob);
-        if (!result->resultCode.isOk()) {
-            return Status::ok();
-        }
-
-        auto upgradedHidlKeyBlob = blob2hidlVec(keyBlob);
-
-        result->resultCode = KS_HANDLE_HIDL_ERROR(dev->exportKey(
-            KeyFormat(format), upgradedHidlKeyBlob, clientId.getData(), appData.getData(), hidlCb));
-        if (!result->resultCode.isOk()) {
-            return Status::ok();
-        }
-    }
+    resultFuture.wait();
     return Status::ok();
 }
 
@@ -1014,8 +807,6 @@
                               bool pruneable, const KeymasterArguments& params,
                               const ::std::vector<uint8_t>& entropy, int32_t uid,
                               OperationResult* result) {
-    auto keyPurpose = static_cast<KeyPurpose>(purpose);
-
     uid_t callingUid = IPCThreadState::self()->getCallingUid();
     uid_t targetUid = getEffectiveUid(uid);
     if (!is_granted_to(callingUid, targetUid)) {
@@ -1033,217 +824,42 @@
         return Status::ok();
     }
 
-    Blob keyBlob;
     String8 name8(name);
-    result->resultCode = mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_KEYMASTER_10);
-    if (result->resultCode == ResponseCode::LOCKED && keyBlob.isSuperEncrypted()) {
-        result->resultCode = ErrorCode::KEY_USER_NOT_AUTHENTICATED;
-    }
-    if (!result->resultCode.isOk()) return Status::ok();
+    Blob keyBlob;
+    Blob charBlob;
+    LockedKeyBlobEntry lockedEntry;
+    ResponseCode rc;
 
-    auto key = blob2hidlVec(keyBlob);
+    std::tie(rc, keyBlob, charBlob, lockedEntry) =
+        mKeyStore->getKeyForName(name8, targetUid, TYPE_KEYMASTER_10);
+
+    if (rc == ResponseCode::LOCKED && keyBlob.isSuperEncrypted()) {
+        return result->resultCode = ErrorCode::KEY_USER_NOT_AUTHENTICATED, Status::ok();
+    }
+    if (rc != ResponseCode::NO_ERROR) return result->resultCode = rc, Status::ok();
+
     auto dev = mKeyStore->getDevice(keyBlob);
     AuthorizationSet opParams = params.getParameters();
     KeyCharacteristics characteristics;
-    result->resultCode = getOperationCharacteristics(key, &dev, opParams, &characteristics);
 
-    if (result->resultCode == ErrorCode::KEY_REQUIRES_UPGRADE) {
-        result->resultCode = upgradeKeyBlob(name, targetUid, opParams, &keyBlob);
-        if (!result->resultCode.isOk()) {
-            return Status::ok();
-        }
-        key = blob2hidlVec(keyBlob);
-        result->resultCode = getOperationCharacteristics(key, &dev, opParams, &characteristics);
-    }
-    if (!result->resultCode.isOk()) {
-        return Status::ok();
-    }
+    std::promise<void> resultPromise;
+    auto resultFuture = resultPromise.get_future();
 
-    // Merge these characteristics with the ones cached when the key was generated or imported
-    Blob charBlob;
-    AuthorizationSet persistedCharacteristics;
-    result->resultCode =
-        mKeyStore->getKeyForName(&charBlob, name8, targetUid, TYPE_KEY_CHARACTERISTICS);
-    if (result->resultCode.isOk()) {
-        // TODO write one shot stream buffer to avoid copying (twice here)
-        std::string charBuffer(reinterpret_cast<const char*>(charBlob.getValue()),
-                               charBlob.getLength());
-        std::stringstream charStream(charBuffer);
-        persistedCharacteristics.Deserialize(&charStream);
-    } else {
-        ALOGD("Unable to read cached characteristics for key");
-    }
+    dev->begin(std::move(lockedEntry), appToken, std::move(keyBlob), std::move(charBlob), pruneable,
+               static_cast<KeyPurpose>(purpose), std::move(opParams), entropy,
+               [&, this](OperationResult result_) {
+                   if (result_.resultCode.isOk() ||
+                       result_.resultCode == ResponseCode::OP_AUTH_NEEDED) {
+                       addOperationDevice(result_.token, dev);
+                   }
+                   if (result) *result = std::move(result_);
+                   resultPromise.set_value();
+               });
 
-    // Replace the sw_enforced set with those persisted to disk, minus hw_enforced
-    AuthorizationSet softwareEnforced = characteristics.softwareEnforced;
-    AuthorizationSet hardwareEnforced = characteristics.hardwareEnforced;
-    persistedCharacteristics.Union(softwareEnforced);
-    persistedCharacteristics.Subtract(hardwareEnforced);
-    characteristics.softwareEnforced = persistedCharacteristics.hidl_data();
-
-    KeyStoreServiceReturnCode authResult;
-    HardwareAuthToken authToken;
-    std::tie(authResult, authToken) =
-        getAuthToken(characteristics, 0 /* no challenge */, keyPurpose,
-                     /*failOnTokenMissing*/ false);
-
-    // If per-operation auth is needed we need to begin the operation and
-    // the client will need to authorize that operation before calling
-    // update. Any other auth issues stop here.
-    if (!authResult.isOk() && authResult != ResponseCode::OP_AUTH_NEEDED) {
-        result->resultCode = authResult;
-        return Status::ok();
-    }
-
-    // Add entropy to the device first.
-    if (entropy.size()) {
-        result->resultCode = KS_HANDLE_HIDL_ERROR(dev->addRngEntropy(entropy));
-        if (!result->resultCode.isOk()) {
-            return Status::ok();
-        }
-    }
-
-    // Create a keyid for this key.
-    km_id_t keyid;
-    if (!enforcement_policy.CreateKeyId(key, &keyid)) {
-        ALOGE("Failed to create a key ID for authorization checking.");
-        result->resultCode = ErrorCode::UNKNOWN_ERROR;
-        return Status::ok();
-    }
-
-    // Check that all key authorization policy requirements are met.
-    AuthorizationSet key_auths = characteristics.hardwareEnforced;
-    key_auths.append(characteristics.softwareEnforced.begin(),
-                     characteristics.softwareEnforced.end());
-
-    result->resultCode =
-        enforcement_policy.AuthorizeOperation(keyPurpose, keyid, key_auths, opParams, authToken,
-                                              0 /* op_handle */, true /* is_begin_operation */);
-    if (!result->resultCode.isOk()) {
-        return Status::ok();
-    }
-
-    // If there are more than kMaxOperations, abort the oldest operation that was started as
-    // pruneable.
-    while (mOperationMap.getOperationCount() >= kMaxOperations) {
-        ALOGD("Reached or exceeded concurrent operations limit");
-        if (!pruneOperation()) {
-            break;
-        }
-    }
-
-    auto hidlCb = [&](ErrorCode ret, const hidl_vec<KeyParameter>& outParams,
-                      uint64_t operationHandle) {
-        result->resultCode = ret;
-        if (!result->resultCode.isOk()) {
-            if (result->resultCode == ErrorCode::INVALID_KEY_BLOB) {
-                log_key_integrity_violation(name8, targetUid);
-            }
-            return;
-        }
-        result->handle = operationHandle;
-        result->outParams = outParams;
-    };
-
-    KeyStoreServiceReturnCode rc =
-        KS_HANDLE_HIDL_ERROR(dev->begin(keyPurpose, key, opParams.hidl_data(), authToken, hidlCb));
-    if (!rc.isOk()) {
-        LOG(ERROR) << "Got error " << rc << " from begin()";
-        result->resultCode = ResponseCode::SYSTEM_ERROR;
-        return Status::ok();
-    }
-
-    rc = result->resultCode;
-
-    // If there are too many operations abort the oldest operation that was
-    // started as pruneable and try again.
-    LOG(INFO) << rc << " " << mOperationMap.hasPruneableOperation();
-    while (rc == ErrorCode::TOO_MANY_OPERATIONS && mOperationMap.hasPruneableOperation()) {
-        LOG(INFO) << "Ran out of operation handles";
-        if (!pruneOperation()) {
-            break;
-        }
-        rc = KS_HANDLE_HIDL_ERROR(
-            dev->begin(keyPurpose, key, opParams.hidl_data(), authToken, hidlCb));
-        if (!rc.isOk()) {
-            LOG(ERROR) << "Got error " << rc << " from begin()";
-            result->resultCode = ResponseCode::SYSTEM_ERROR;
-            return Status::ok();
-        }
-        rc = result->resultCode;
-    }
-    if (!rc.isOk()) {
-        result->resultCode = rc;
-        return Status::ok();
-    }
-
-    VerificationToken verificationToken;
-    if (authResult.isOk() && authToken.mac.size() &&
-        dev->halVersion().securityLevel == SecurityLevel::STRONGBOX) {
-        // This operation needs an auth token, but the device is a STRONGBOX, so it can't check the
-        // timestamp in the auth token.  Get a VerificationToken from the TEE, which will be passed
-        // to update() and begin().
-        rc = KS_HANDLE_HIDL_ERROR(mKeyStore->getDevice(SecurityLevel::TRUSTED_ENVIRONMENT)
-                                      ->verifyAuthorization(result->handle,
-                                                            {} /* parametersToVerify */, authToken,
-                                                            [&](auto error, const auto& token) {
-                                                                result->resultCode = error;
-                                                                verificationToken = token;
-                                                            }));
-
-        if (!rc.isOk()) result->resultCode = rc;
-        if (!result->resultCode.isOk()) {
-            LOG(ERROR) << "Failed to verify authorization " << rc << " from begin()";
-            rc = KS_HANDLE_HIDL_ERROR(dev->abort(result->handle));
-            if (!rc.isOk()) {
-                LOG(ERROR) << "Failed to abort operation " << rc << " from begin()";
-            }
-            return Status::ok();
-        }
-    }
-
-    // Note: The operation map takes possession of the contents of "characteristics".
-    // It is safe to use characteristics after the following line but it will be empty.
-    sp<IBinder> operationToken =
-        mOperationMap.addOperation(result->handle, keyid, keyPurpose, dev, appToken,
-                                   std::move(characteristics), params.getParameters(), pruneable);
-    assert(characteristics.hardwareEnforced.size() == 0);
-    assert(characteristics.softwareEnforced.size() == 0);
-    result->token = operationToken;
-
-    mOperationMap.setOperationAuthToken(operationToken, std::move(authToken));
-    mOperationMap.setOperationVerificationToken(operationToken, std::move(verificationToken));
-
-    // Return the authentication lookup result. If this is a per operation
-    // auth'd key then the resultCode will be ::OP_AUTH_NEEDED and the
-    // application should get an auth token using the handle before the
-    // first call to update, which will fail if keystore hasn't received the
-    // auth token.
-    if (result->resultCode == ErrorCode::OK) {
-        result->resultCode = authResult;
-    }
-
-    // Other result fields were set in the begin operation's callback.
+    resultFuture.wait();
     return Status::ok();
 }
 
-void KeyStoreService::appendConfirmationTokenIfNeeded(const KeyCharacteristics& keyCharacteristics,
-                                                      std::vector<KeyParameter>* params) {
-    if (!(containsTag(keyCharacteristics.softwareEnforced, Tag::TRUSTED_CONFIRMATION_REQUIRED) ||
-          containsTag(keyCharacteristics.hardwareEnforced, Tag::TRUSTED_CONFIRMATION_REQUIRED))) {
-        return;
-    }
-
-    hidl_vec<uint8_t> confirmationToken = mConfirmationManager->getLatestConfirmationToken();
-    if (confirmationToken.size() == 0) {
-        return;
-    }
-
-    params->push_back(
-        Authorization(keymaster::TAG_CONFIRMATION_TOKEN, std::move(confirmationToken)));
-    ALOGD("Appending confirmation token\n");
-}
-
 Status KeyStoreService::update(const sp<IBinder>& token, const KeymasterArguments& params,
                                const ::std::vector<uint8_t>& data, OperationResult* result) {
     if (!checkAllowedOperationParams(params.getParameters())) {
@@ -1251,132 +867,70 @@
         return Status::ok();
     }
 
-    auto getOpResult = mOperationMap.getOperation(token);
-    if (!getOpResult.isOk()) {
-        result->resultCode = ErrorCode::INVALID_OPERATION_HANDLE;
+    std::promise<void> resultPromise;
+    auto resultFuture = resultPromise.get_future();
+
+    auto dev = getOperationDevice(token);
+    if (!dev) {
+        *result = operationFailed(ErrorCode::INVALID_OPERATION_HANDLE);
         return Status::ok();
     }
-    const auto& op = getOpResult.value();
 
-    HardwareAuthToken authToken;
-    std::tie(result->resultCode, authToken) = getOperationAuthTokenIfNeeded(token);
-    if (!result->resultCode.isOk()) return Status::ok();
-
-    // Check that all key authorization policy requirements are met.
-    AuthorizationSet key_auths(op.characteristics.hardwareEnforced);
-    key_auths.append(op.characteristics.softwareEnforced.begin(),
-                     op.characteristics.softwareEnforced.end());
-
-    result->resultCode = enforcement_policy.AuthorizeOperation(
-        op.purpose, op.keyid, key_auths, params.getParameters(), authToken, op.handle,
-        false /* is_begin_operation */);
-    if (!result->resultCode.isOk()) return Status::ok();
-
-    std::vector<KeyParameter> inParams = params.getParameters();
-
-    auto hidlCb = [&](ErrorCode ret, uint32_t inputConsumed,
-                      const hidl_vec<KeyParameter>& outParams,
-                      const ::std::vector<uint8_t>& output) {
-        result->resultCode = ret;
-        if (result->resultCode.isOk()) {
-            result->inputConsumed = inputConsumed;
-            result->outParams = outParams;
-            result->data = output;
+    dev->update(token, params.getParameters(), data, [&](OperationResult result_) {
+        if (!result_.resultCode.isOk()) {
+            removeOperationDevice(token);
         }
-    };
+        if (result) *result = std::move(result_);
+        resultPromise.set_value();
+    });
 
-    KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(
-        op.device->update(op.handle, inParams, data, authToken, op.verificationToken, hidlCb));
-
-    // just a reminder: on success result->resultCode was set in the callback. So we only overwrite
-    // it if there was a communication error indicated by the ErrorCode.
-    if (!rc.isOk()) {
-        result->resultCode = rc;
-        // removeOperation() will free the memory 'op' used, so the order is important
-        mAuthTokenTable.MarkCompleted(op.handle);
-        mOperationMap.removeOperation(token, /* wasOpSuccessful */ false);
-    }
-
+    resultFuture.wait();
     return Status::ok();
 }
 
 Status KeyStoreService::finish(const sp<IBinder>& token, const KeymasterArguments& params,
                                const ::std::vector<uint8_t>& signature,
                                const ::std::vector<uint8_t>& entropy, OperationResult* result) {
-    auto getOpResult = mOperationMap.getOperation(token);
-    if (!getOpResult.isOk()) {
-        result->resultCode = ErrorCode::INVALID_OPERATION_HANDLE;
-        return Status::ok();
-    }
-    const auto& op = std::move(getOpResult.value());
     if (!checkAllowedOperationParams(params.getParameters())) {
         result->resultCode = ErrorCode::INVALID_ARGUMENT;
         return Status::ok();
     }
 
-    HardwareAuthToken authToken;
-    std::tie(result->resultCode, authToken) = getOperationAuthTokenIfNeeded(token);
-    if (!result->resultCode.isOk()) return Status::ok();
+    std::promise<void> resultPromise;
+    auto resultFuture = resultPromise.get_future();
 
-    if (entropy.size()) {
-        result->resultCode = KS_HANDLE_HIDL_ERROR(op.device->addRngEntropy(entropy));
-        if (!result->resultCode.isOk()) {
-            return Status::ok();
-        }
+    auto dev = getOperationDevice(token);
+    if (!dev) {
+        *result = operationFailed(ErrorCode::INVALID_OPERATION_HANDLE);
+        return Status::ok();
     }
 
-    // Check that all key authorization policy requirements are met.
-    AuthorizationSet key_auths(op.characteristics.hardwareEnforced);
-    key_auths.append(op.characteristics.softwareEnforced.begin(),
-                     op.characteristics.softwareEnforced.end());
+    dev->finish(token, params.getParameters(), {}, signature, entropy,
+                [&](OperationResult result_) {
+                    if (!result_.resultCode.isOk()) {
+                        removeOperationDevice(token);
+                    }
+                    if (result) *result = std::move(result_);
+                    resultPromise.set_value();
+                });
 
-    std::vector<KeyParameter> inParams = params.getParameters();
-    appendConfirmationTokenIfNeeded(op.characteristics, &inParams);
-
-    result->resultCode = enforcement_policy.AuthorizeOperation(
-        op.purpose, op.keyid, key_auths, params.getParameters(), authToken, op.handle,
-        false /* is_begin_operation */);
-    if (!result->resultCode.isOk()) return Status::ok();
-
-    auto hidlCb = [&](ErrorCode ret, const hidl_vec<KeyParameter>& outParams,
-                      const ::std::vector<uint8_t>& output) {
-        result->resultCode = ret;
-        if (result->resultCode.isOk()) {
-            result->outParams = outParams;
-            result->data = output;
-        }
-    };
-
-    KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(
-        op.device->finish(op.handle, inParams,
-                          ::std::vector<uint8_t>() /* TODO(swillden): wire up input to finish() */,
-                          signature, authToken, op.verificationToken, hidlCb));
-
-    bool wasOpSuccessful = true;
-    // just a reminder: on success result->resultCode was set in the callback. So we only overwrite
-    // it if there was a communication error indicated by the ErrorCode.
-    if (!rc.isOk()) {
-        result->resultCode = rc;
-        wasOpSuccessful = false;
-    }
-
-    // removeOperation() will free the memory 'op' used, so the order is important
-    mAuthTokenTable.MarkCompleted(op.handle);
-    mOperationMap.removeOperation(token, wasOpSuccessful);
+    resultFuture.wait();
     return Status::ok();
 }
 
 Status KeyStoreService::abort(const sp<IBinder>& token, int32_t* aidl_return) {
-    auto getOpResult = mOperationMap.removeOperation(token, false /* wasOpSuccessful */);
-    if (!getOpResult.isOk()) {
+    auto dev = getOperationDevice(token);
+    if (!dev) {
         *aidl_return = static_cast<int32_t>(ErrorCode::INVALID_OPERATION_HANDLE);
         return Status::ok();
     }
-    auto op = std::move(getOpResult.value());
-    mAuthTokenTable.MarkCompleted(op.handle);
+    std::promise<KeyStoreServiceReturnCode> resultPromise;
+    auto resultFuture = resultPromise.get_future();
 
-    ErrorCode error_code = KS_HANDLE_HIDL_ERROR(op.device->abort(op.handle));
-    *aidl_return = static_cast<int32_t>(KeyStoreServiceReturnCode(error_code));
+    dev->abort(token, [&](KeyStoreServiceReturnCode rc) { resultPromise.set_value(rc); });
+
+    resultFuture.wait();
+    *aidl_return = int32_t(resultFuture.get());
     return Status::ok();
 }
 
@@ -1403,7 +957,8 @@
         return Status::ok();
     }
 
-    mAuthTokenTable.AddAuthenticationToken(hidlVec2AuthToken(hidl_vec<uint8_t>(authTokenAsVector)));
+    mKeyStore->getAuthTokenTable().AddAuthenticationToken(
+        hidlVec2AuthToken(hidl_vec<uint8_t>(authTokenAsVector)));
     *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR);
     return Status::ok();
 }
@@ -1463,33 +1018,35 @@
         return Status::ok();
     }
 
-    Blob keyBlob;
     String8 name8(name);
-    rc = mKeyStore->getKeyForName(&keyBlob, name8, callingUid, TYPE_KEYMASTER_10);
-    if (!rc.isOk()) {
-        *aidl_return = static_cast<int32_t>(rc);
-        return Status::ok();
-    }
+    Blob keyBlob;
+    Blob charBlob;
+    LockedKeyBlobEntry lockedEntry;
 
-    KeyStoreServiceReturnCode error;
-    auto hidlCb = [&](ErrorCode ret, const hidl_vec<hidl_vec<uint8_t>>& certChain) {
-        error = ret;
-        if (!error.isOk()) {
+    std::tie(rc, keyBlob, charBlob, lockedEntry) =
+        mKeyStore->getKeyForName(name8, callingUid, TYPE_KEYMASTER_10);
+
+    std::promise<KeyStoreServiceReturnCode> resultPromise;
+    auto resultFuture = resultPromise.get_future();
+
+    auto worker_cb = [&](Return<void> rc,
+                         std::tuple<ErrorCode, hidl_vec<hidl_vec<uint8_t>>>&& hidlResult) {
+        auto& [ret, certChain] = hidlResult;
+        if (!rc.isOk()) {
+            resultPromise.set_value(ResponseCode::SYSTEM_ERROR);
             return;
         }
-        if (chain) {
+        if (ret == ErrorCode::OK && chain) {
             *chain = KeymasterCertificateChain(certChain);
         }
+        resultPromise.set_value(ret);
     };
-
-    auto hidlKey = blob2hidlVec(keyBlob);
     auto dev = mKeyStore->getDevice(keyBlob);
-    rc = KS_HANDLE_HIDL_ERROR(dev->attestKey(hidlKey, mutableParams.hidl_data(), hidlCb));
-    if (!rc.isOk()) {
-        *aidl_return = static_cast<int32_t>(rc);
-        return Status::ok();
-    }
-    *aidl_return = static_cast<int32_t>(error);
+    auto hidlKey = blob2hidlVec(keyBlob);
+    dev->attestKey(std::move(hidlKey), mutableParams.hidl_data(), worker_cb);
+
+    resultFuture.wait();
+    *aidl_return = static_cast<int32_t>(resultFuture.get());
     return Status::ok();
 }
 
@@ -1533,15 +1090,13 @@
     }
 
     // Generate temporary key.
-    sp<Keymaster> dev = mKeyStore->getDevice(SecurityLevel::TRUSTED_ENVIRONMENT);
+    auto dev = mKeyStore->getDevice(SecurityLevel::TRUSTED_ENVIRONMENT);
 
     if (!dev) {
         *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
         return Status::ok();
     }
 
-    KeyStoreServiceReturnCode error;
-    ::std::vector<uint8_t> hidlKey;
 
     AuthorizationSet keyCharacteristics;
     keyCharacteristics.push_back(TAG_PURPOSE, KeyPurpose::VERIFY);
@@ -1549,54 +1104,55 @@
     keyCharacteristics.push_back(TAG_DIGEST, Digest::SHA_2_256);
     keyCharacteristics.push_back(TAG_NO_AUTH_REQUIRED);
     keyCharacteristics.push_back(TAG_EC_CURVE, EcCurve::P_256);
-    auto generateHidlCb = [&](ErrorCode ret, const ::std::vector<uint8_t>& hidlKeyBlob,
-                              const KeyCharacteristics&) {
-        error = ret;
-        if (!error.isOk()) {
-            return;
-        }
-        hidlKey = hidlKeyBlob;
-    };
 
-    rc = KS_HANDLE_HIDL_ERROR(dev->generateKey(keyCharacteristics.hidl_data(), generateHidlCb));
-    if (!rc.isOk()) {
-        *aidl_return = static_cast<int32_t>(rc);
-        return Status::ok();
-    }
-    if (!error.isOk()) {
-        *aidl_return = static_cast<int32_t>(error);
-        return Status::ok();
-    }
+    std::promise<KeyStoreServiceReturnCode> resultPromise;
+    auto resultFuture = resultPromise.get_future();
 
-    // Attest key and device IDs.
-    auto attestHidlCb = [&](ErrorCode ret, const hidl_vec<hidl_vec<uint8_t>>& certChain) {
-        error = ret;
-        if (!error.isOk()) {
-            return;
-        }
-        *chain = ::android::security::keymaster::KeymasterCertificateChain(certChain);
-    };
-    KeyStoreServiceReturnCode attestationRc =
-        KS_HANDLE_HIDL_ERROR(dev->attestKey(hidlKey, mutableParams.hidl_data(), attestHidlCb));
+    dev->generateKey(
+        keyCharacteristics.hidl_data(),
+        [&, dev](Return<void> rc,
+                 std::tuple<ErrorCode, ::std::vector<uint8_t>, KeyCharacteristics>&& hidlResult) {
+            auto& [ret, hidlKeyBlob_, dummyCharacteristics] = hidlResult;
+            auto hidlKeyBlob = std::move(hidlKeyBlob_);
+            if (!rc.isOk()) {
+                resultPromise.set_value(ResponseCode::SYSTEM_ERROR);
+                return;
+            }
+            if (ret != ErrorCode::OK) {
+                resultPromise.set_value(ret);
+                return;
+            }
+            dev->attestKey(
+                hidlKeyBlob, mutableParams.hidl_data(),
+                [&, dev,
+                 hidlKeyBlob](Return<void> rc,
+                              std::tuple<ErrorCode, hidl_vec<hidl_vec<uint8_t>>>&& hidlResult) {
+                    auto& [ret, certChain] = hidlResult;
+                    // shedule temp key for deletion
+                    dev->deleteKey(std::move(hidlKeyBlob), [](Return<ErrorCode> rc) {
+                        // log error but don't return an error
+                        KS_HANDLE_HIDL_ERROR(rc);
+                    });
+                    if (!rc.isOk()) {
+                        resultPromise.set_value(ResponseCode::SYSTEM_ERROR);
+                        return;
+                    }
+                    if (ret == ErrorCode::OK && chain) {
+                        *chain =
+                            ::android::security::keymaster::KeymasterCertificateChain(certChain);
+                    }
+                    resultPromise.set_value(ret);
+                });
+        });
 
-    // Delete temporary key.
-    KeyStoreServiceReturnCode deletionRc = KS_HANDLE_HIDL_ERROR(dev->deleteKey(hidlKey));
-
-    if (!attestationRc.isOk()) {
-        *aidl_return = static_cast<int32_t>(attestationRc);
-        return Status::ok();
-    }
-    if (!error.isOk()) {
-        *aidl_return = static_cast<int32_t>(error);
-        return Status::ok();
-    }
-    *aidl_return = static_cast<int32_t>(deletionRc);
+    resultFuture.wait();
+    *aidl_return = static_cast<int32_t>(resultFuture.get());
     return Status::ok();
 }
 
 Status KeyStoreService::onDeviceOffBody(int32_t* aidl_return) {
     // TODO(tuckeris): add permission check.  This should be callable from ClockworkHome only.
-    mAuthTokenTable.onDeviceOffBody();
+    mKeyStore->getAuthTokenTable().onDeviceOffBody();
     *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR);
     return Status::ok();
 }
@@ -1616,80 +1172,48 @@
         return AIDL_RETURN(ResponseCode::PERMISSION_DENIED);
     }
 
-    Blob wrappingKeyBlob;
     String8 wrappingKeyName8(wrappingKeyAlias);
-    KeyStoreServiceReturnCode rc =
-        mKeyStore->getKeyForName(&wrappingKeyBlob, wrappingKeyName8, callingUid, TYPE_KEYMASTER_10);
-    if (!rc.isOk()) {
+
+    KeyStoreServiceReturnCode rc;
+    Blob wrappingKeyBlob;
+    Blob wrappingCharBlob;
+    LockedKeyBlobEntry wrappingLockedEntry;
+
+    std::tie(rc, wrappingKeyBlob, wrappingCharBlob, wrappingLockedEntry) =
+        mKeyStore->getKeyForName(wrappingKeyName8, callingUid, TYPE_KEYMASTER_10);
+    if (!rc) {
         return AIDL_RETURN(rc);
     }
 
+    String8 wrappedKeyName8(wrappedKeyAlias);
+    auto wrappedLockedEntry =
+        mKeyStore->getLockedBlobEntryIfNotExists(wrappedKeyName8.string(), callingUid);
+    if (!wrappedLockedEntry) {
+        return AIDL_RETURN(ResponseCode::KEY_ALREADY_EXISTS);
+    }
+
     SecurityLevel securityLevel = wrappingKeyBlob.getSecurityLevel();
     auto dev = mKeyStore->getDevice(securityLevel);
     if (!dev) {
         return AIDL_RETURN(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
     }
 
-    auto hidlWrappingKey = blob2hidlVec(wrappingKeyBlob);
-    String8 wrappedKeyAlias8(wrappedKeyAlias);
+    std::promise<KeyStoreServiceReturnCode> resultPromise;
+    auto resultFuture = resultPromise.get_future();
 
-    KeyStoreServiceReturnCode error;
+    dev->importWrappedKey(
+        std::move(wrappingLockedEntry), std::move(wrappedLockedEntry), wrappedKey, maskingKey,
+        params.getParameters(), std::move(wrappingKeyBlob), std::move(wrappingCharBlob), rootSid,
+        fingerprintSid, [&](KeyStoreServiceReturnCode rc, KeyCharacteristics keyCharacteristics) {
+            if (rc.isOk() && outCharacteristics) {
+                *outCharacteristics =
+                    ::android::security::keymaster::KeyCharacteristics(keyCharacteristics);
+            }
+            resultPromise.set_value(rc);
+        });
 
-    auto hidlCb = [&](ErrorCode ret, const ::std::vector<uint8_t>& keyBlob,
-                      const KeyCharacteristics& keyCharacteristics) {
-        error = ret;
-        if (!error.isOk()) {
-            return;
-        }
-        if (outCharacteristics) {
-            *outCharacteristics =
-                ::android::security::keymaster::KeyCharacteristics(keyCharacteristics);
-        }
-
-        // Write the key:
-        String8 filename(
-            mKeyStore->getKeyNameForUidWithDir(wrappedKeyAlias8, callingUid, ::TYPE_KEYMASTER_10));
-
-        Blob ksBlob(&keyBlob[0], keyBlob.size(), nullptr, 0, ::TYPE_KEYMASTER_10);
-        ksBlob.setSecurityLevel(securityLevel);
-
-        if (containsTag(keyCharacteristics.hardwareEnforced, Tag::USER_SECURE_ID)) {
-            ksBlob.setSuperEncrypted(true);
-        }
-
-        error = mKeyStore->put(filename.string(), &ksBlob, get_user_id(callingUid));
-    };
-
-    rc = KS_HANDLE_HIDL_ERROR(dev->importWrappedKey(wrappedKey, hidlWrappingKey, maskingKey,
-                                                    params.getParameters(), rootSid, fingerprintSid,
-                                                    hidlCb));
-
-    // possible hidl error
-    if (!rc.isOk()) {
-        return AIDL_RETURN(rc);
-    }
-    // now check error from callback
-    if (!error.isOk()) {
-        return AIDL_RETURN(error);
-    }
-
-    // Write the characteristics:
-    String8 cFilename(mKeyStore->getKeyNameForUidWithDir(wrappedKeyAlias8, callingUid,
-                                                         ::TYPE_KEY_CHARACTERISTICS));
-
-    AuthorizationSet opParams = params.getParameters();
-    std::stringstream kcStream;
-    opParams.Serialize(&kcStream);
-    if (kcStream.bad()) {
-        return AIDL_RETURN(ResponseCode::SYSTEM_ERROR);
-    }
-    auto kcBuf = kcStream.str();
-
-    Blob charBlob(reinterpret_cast<const uint8_t*>(kcBuf.data()), kcBuf.size(), nullptr, 0,
-                  ::TYPE_KEY_CHARACTERISTICS);
-    charBlob.setSecurityLevel(securityLevel);
-
-    return AIDL_RETURN(mKeyStore->put(cFilename.string(), &charBlob, get_user_id(callingUid)));
+    resultFuture.wait();
+    return AIDL_RETURN(resultFuture.get());
 }
 
 Status KeyStoreService::presentConfirmationPrompt(const sp<IBinder>& listener,
@@ -1697,35 +1221,17 @@
                                                   const ::std::vector<uint8_t>& extraData,
                                                   const String16& locale, int32_t uiOptionsAsFlags,
                                                   int32_t* aidl_return) {
-    return mConfirmationManager->presentConfirmationPrompt(listener, promptText, extraData, locale,
-                                                           uiOptionsAsFlags, aidl_return);
+    return mKeyStore->getConfirmationManager().presentConfirmationPrompt(
+        listener, promptText, extraData, locale, uiOptionsAsFlags, aidl_return);
 }
 
 Status KeyStoreService::cancelConfirmationPrompt(const sp<IBinder>& listener,
                                                  int32_t* aidl_return) {
-    return mConfirmationManager->cancelConfirmationPrompt(listener, aidl_return);
+    return mKeyStore->getConfirmationManager().cancelConfirmationPrompt(listener, aidl_return);
 }
 
 Status KeyStoreService::isConfirmationPromptSupported(bool* aidl_return) {
-    return mConfirmationManager->isConfirmationPromptSupported(aidl_return);
-}
-
-/**
- * Prune the oldest pruneable operation.
- */
-bool KeyStoreService::pruneOperation() {
-    sp<IBinder> oldest = mOperationMap.getOldestPruneableOperation();
-    ALOGD("Trying to prune operation %p", oldest.get());
-    size_t op_count_before_abort = mOperationMap.getOperationCount();
-    // We mostly ignore errors from abort() because all we care about is whether at least
-    // one operation has been removed.
-    int32_t abort_error;
-    abort(oldest, &abort_error);
-    if (mOperationMap.getOperationCount() >= op_count_before_abort) {
-        ALOGE("Failed to abort pruneable operation %p, error: %d", oldest.get(), abort_error);
-        return false;
-    }
-    return true;
+    return mKeyStore->getConfirmationManager().isConfirmationPromptSupported(aidl_return);
 }
 
 /**
@@ -1838,182 +1344,9 @@
     return true;
 }
 
-ErrorCode KeyStoreService::getOperationCharacteristics(const hidl_vec<uint8_t>& key,
-                                                       sp<Keymaster>* dev,
-                                                       const AuthorizationSet& params,
-                                                       KeyCharacteristics* out) {
-    ::std::vector<uint8_t> clientId;
-    ::std::vector<uint8_t> appData;
-    for (auto param : params) {
-        if (param.tag == Tag::APPLICATION_ID) {
-            clientId = authorizationValue(TAG_APPLICATION_ID, param).value();
-        } else if (param.tag == Tag::APPLICATION_DATA) {
-            appData = authorizationValue(TAG_APPLICATION_DATA, param).value();
-        }
-    }
-    ErrorCode error = ErrorCode::OK;
-
-    auto hidlCb = [&](ErrorCode ret, const KeyCharacteristics& keyCharacteristics) {
-        error = ret;
-        if (error != ErrorCode::OK) {
-            return;
-        }
-        if (out) *out = keyCharacteristics;
-    };
-
-    ErrorCode rc =
-        KS_HANDLE_HIDL_ERROR((*dev)->getKeyCharacteristics(key, clientId, appData, hidlCb));
-    if (rc != ErrorCode::OK) {
-        return rc;
-    }
-    return error;
-}
-
-/**
- * Get the auth token for this operation from the auth token table.
- *
- * Returns ResponseCode::NO_ERROR if the auth token was set or none was required.
- *         ::OP_AUTH_NEEDED if it is a per op authorization, no
- *         authorization token exists for that operation and
- *         failOnTokenMissing is false.
- *         KM_ERROR_KEY_USER_NOT_AUTHENTICATED if there is no valid auth
- *         token for the operation
- */
-std::pair<KeyStoreServiceReturnCode, HardwareAuthToken>
-KeyStoreService::getAuthToken(const KeyCharacteristics& characteristics, uint64_t handle,
-                              KeyPurpose purpose, bool failOnTokenMissing) {
-
-    AuthorizationSet allCharacteristics(characteristics.softwareEnforced);
-    allCharacteristics.append(characteristics.hardwareEnforced.begin(),
-                              characteristics.hardwareEnforced.end());
-
-    const HardwareAuthToken* authToken = nullptr;
-    AuthTokenTable::Error err = mAuthTokenTable.FindAuthorization(
-        allCharacteristics, static_cast<KeyPurpose>(purpose), handle, &authToken);
-
-    KeyStoreServiceReturnCode rc;
-
-    switch (err) {
-    case AuthTokenTable::OK:
-    case AuthTokenTable::AUTH_NOT_REQUIRED:
-        rc = ResponseCode::NO_ERROR;
-        break;
-
-    case AuthTokenTable::AUTH_TOKEN_NOT_FOUND:
-    case AuthTokenTable::AUTH_TOKEN_EXPIRED:
-    case AuthTokenTable::AUTH_TOKEN_WRONG_SID:
-        ALOGE("getAuthToken failed: %d", err);  // STOPSHIP: debug only, to be removed
-        rc = ErrorCode::KEY_USER_NOT_AUTHENTICATED;
-        break;
-
-    case AuthTokenTable::OP_HANDLE_REQUIRED:
-        rc = failOnTokenMissing ? KeyStoreServiceReturnCode(ErrorCode::KEY_USER_NOT_AUTHENTICATED)
-                                : KeyStoreServiceReturnCode(ResponseCode::OP_AUTH_NEEDED);
-        break;
-
-    default:
-        ALOGE("Unexpected FindAuthorization return value %d", err);
-        rc = ErrorCode::INVALID_ARGUMENT;
-    }
-
-    return {rc, authToken ? std::move(*authToken) : HardwareAuthToken()};
-}
-
-/**
- * Add the auth token for the operation to the param list if the operation
- * requires authorization. Uses the cached result in the OperationMap if available
- * otherwise gets the token from the AuthTokenTable and caches the result.
- *
- * Returns ResponseCode::NO_ERROR if the auth token was added or not needed.
- *         KM_ERROR_KEY_USER_NOT_AUTHENTICATED if the operation is not
- *         authenticated.
- *         KM_ERROR_INVALID_OPERATION_HANDLE if token is not a valid
- *         operation token.
- */
-std::pair<KeyStoreServiceReturnCode, const HardwareAuthToken&>
-KeyStoreService::getOperationAuthTokenIfNeeded(const sp<IBinder>& token) {
-    static HardwareAuthToken emptyToken = {};
-
-    auto getOpResult = mOperationMap.getOperation(token);
-    if (!getOpResult.isOk()) return {ErrorCode::INVALID_OPERATION_HANDLE, emptyToken};
-    const auto& op = getOpResult.value();
-
-    if (!op.hasAuthToken()) {
-        KeyStoreServiceReturnCode rc;
-        HardwareAuthToken found;
-        std::tie(rc, found) = getAuthToken(op.characteristics, op.handle, op.purpose);
-        if (!rc.isOk()) return {rc, emptyToken};
-        mOperationMap.setOperationAuthToken(token, std::move(found));
-    }
-
-    return {ResponseCode::NO_ERROR, op.authToken};
-}
-
-KeyStoreServiceReturnCode KeyStoreService::upgradeKeyBlob(const String16& name, uid_t uid,
-                                                          const AuthorizationSet& params,
-                                                          Blob* blob) {
-    // Read the blob rather than assuming the caller provided the right name/uid/blob triplet.
-    String8 name8(name);
-    KeyStoreServiceReturnCode responseCode =
-        mKeyStore->getKeyForName(blob, name8, uid, TYPE_KEYMASTER_10);
-    if (responseCode != ResponseCode::NO_ERROR) {
-        return responseCode;
-    }
-    ALOGI("upgradeKeyBlob %s %d", name8.string(), uid);
-
-    auto hidlKey = blob2hidlVec(*blob);
-    auto dev = mKeyStore->getDevice(*blob);
-
-    KeyStoreServiceReturnCode error;
-    auto hidlCb = [&](ErrorCode ret, const ::std::vector<uint8_t>& upgradedKeyBlob) {
-        error = ret;
-        if (!error.isOk()) {
-            if (error == ErrorCode::INVALID_KEY_BLOB) {
-                log_key_integrity_violation(name8, uid);
-            }
-            return;
-        }
-
-        auto filename = mKeyStore->getBlobFileNameIfExists(name8, uid, ::TYPE_KEYMASTER_10);
-        if (!filename.isOk()) {
-            ALOGI("trying to upgrade a non existing blob");
-            return;
-        }
-        error = mKeyStore->del(filename.value().string(), ::TYPE_ANY, get_user_id(uid));
-        if (!error.isOk()) {
-            ALOGI("upgradeKeyBlob keystore->del failed %d", (int)error);
-            return;
-        }
-
-        Blob newBlob(&upgradedKeyBlob[0], upgradedKeyBlob.size(), nullptr /* info */,
-                     0 /* infoLength */, ::TYPE_KEYMASTER_10);
-        newBlob.setSecurityLevel(blob->getSecurityLevel());
-        newBlob.setEncrypted(blob->isEncrypted());
-        newBlob.setSuperEncrypted(blob->isSuperEncrypted());
-        newBlob.setCriticalToDeviceEncryption(blob->isCriticalToDeviceEncryption());
-
-        error = mKeyStore->put(filename.value().string(), &newBlob, get_user_id(uid));
-        if (!error.isOk()) {
-            ALOGI("upgradeKeyBlob keystore->put failed %d", (int)error);
-            return;
-        }
-
-        // Re-read blob for caller.  We can't use newBlob because writing it modified it.
-        error = mKeyStore->getKeyForName(blob, name8, uid, TYPE_KEYMASTER_10);
-    };
-
-    KeyStoreServiceReturnCode rc =
-        KS_HANDLE_HIDL_ERROR(dev->upgradeKey(hidlKey, params.hidl_data(), hidlCb));
-    if (!rc.isOk()) {
-        return rc;
-    }
-
-    return error;
-}
-
 Status KeyStoreService::onKeyguardVisibilityChanged(bool isShowing, int32_t userId,
                                                     int32_t* aidl_return) {
-    enforcement_policy.set_device_locked(isShowing, userId);
+    mKeyStore->getEnforcementPolicy().set_device_locked(isShowing, userId);
     *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR);
 
     return Status::ok();
diff --git a/keystore/key_store_service.h b/keystore/key_store_service.h
index 7a48be7..29369d0 100644
--- a/keystore/key_store_service.h
+++ b/keystore/key_store_service.h
@@ -27,6 +27,14 @@
 #include "operation.h"
 #include "permissions.h"
 
+#include <keystore/ExportResult.h>
+#include <keystore/KeyCharacteristics.h>
+#include <keystore/KeymasterArguments.h>
+#include <keystore/KeymasterBlob.h>
+#include <keystore/KeymasterCertificateChain.h>
+#include <keystore/OperationResult.h>
+#include <keystore/keystore_return_types.h>
+
 namespace keystore {
 
 // Class provides implementation for generated BnKeystoreService.h based on
@@ -34,12 +42,9 @@
 // java/android/security/IKeystoreService.aidl Note that all generated methods return binder::Status
 // and use last arguments to send actual result to the caller. Private methods don't need to handle
 // binder::Status. Input parameters cannot be null unless annotated with @nullable in .aidl file.
-class KeyStoreService : public android::security::BnKeystoreService,
-                        android::IBinder::DeathRecipient {
+class KeyStoreService : public android::security::BnKeystoreService {
   public:
-    explicit KeyStoreService(KeyStore* keyStore)
-        : mKeyStore(keyStore), mOperationMap(this),
-          mConfirmationManager(new ConfirmationManager(this)) {}
+    explicit KeyStoreService(sp<KeyStore> keyStore) : mKeyStore(keyStore) {}
     virtual ~KeyStoreService() = default;
 
     void binderDied(const android::wp<android::IBinder>& who);
@@ -149,17 +154,12 @@
     ::android::binder::Status isConfirmationPromptSupported(bool* _aidl_return) override;
 
     ::android::binder::Status onKeyguardVisibilityChanged(bool isShowing, int32_t userId,
-                                                          int32_t* _aidl_return);
+                                                          int32_t* _aidl_return) override;
 
   private:
     static const int32_t UID_SELF = -1;
 
     /**
-     * Prune the oldest pruneable operation.
-     */
-    bool pruneOperation();
-
-    /**
      * Get the effective target uid for a binder operation that takes an
      * optional uid as the target.
      */
@@ -206,41 +206,6 @@
      */
     bool checkAllowedOperationParams(const hidl_vec<KeyParameter>& params);
 
-    ErrorCode getOperationCharacteristics(const hidl_vec<uint8_t>& key, sp<Keymaster>* dev,
-                                          const AuthorizationSet& params, KeyCharacteristics* out);
-
-    /**
-     * Get the auth token for this operation from the auth token table.
-     *
-     * Returns NO_ERROR if the auth token was found or none was required.  If not needed, the
-     *             token will be empty (which keymaster interprets as no auth token).
-     *         OP_AUTH_NEEDED if it is a per op authorization, no authorization token exists for
-     *             that operation and  failOnTokenMissing is false.
-     *         KM_ERROR_KEY_USER_NOT_AUTHENTICATED if there is no valid auth token for the operation
-     */
-    std::pair<KeyStoreServiceReturnCode, HardwareAuthToken>
-    getAuthToken(const KeyCharacteristics& characteristics, uint64_t handle, KeyPurpose purpose,
-                 bool failOnTokenMissing = true);
-
-    /**
-     * Get the auth token for the operation if the operation requires authorization. Uses the cached
-     * result in the OperationMap if available otherwise gets the token from the AuthTokenTable and
-     * caches the result.
-     *
-     * Returns NO_ERROR if the auth token was found or not needed.  If not needed, the token will
-     *             be empty (which keymaster interprets as no auth token).
-     *         KM_ERROR_KEY_USER_NOT_AUTHENTICATED if the operation is not authenticated.
-     *         KM_ERROR_INVALID_OPERATION_HANDLE if token is not a valid operation token.
-     */
-    std::pair<KeyStoreServiceReturnCode, const HardwareAuthToken&>
-    getOperationAuthTokenIfNeeded(const sp<android::IBinder>& token);
-
-    /**
-     * Translate a result value to a legacy return value. All keystore errors are
-     * preserved and keymaster errors become SYSTEM_ERRORs
-     */
-    KeyStoreServiceReturnCode translateResultToLegacyResult(int32_t result);
-
     void addLegacyBeginParams(const android::String16& name, AuthorizationSet* params);
 
     KeyStoreServiceReturnCode doLegacySignVerify(const android::String16& name,
@@ -250,27 +215,32 @@
                                                  KeyPurpose purpose);
 
     /**
-     * Upgrade a key blob under alias "name", returning the new blob in "blob".  If "blob"
-     * previously contained data, it will be overwritten.
-     *
-     * Returns ::NO_ERROR if the key was upgraded successfully.
-     *         KM_ERROR_VERSION_MISMATCH if called on a key whose patch level is greater than or
-     *         equal to the current system patch level.
-     */
-    KeyStoreServiceReturnCode upgradeKeyBlob(const android::String16& name, uid_t targetUid,
-                                             const AuthorizationSet& params, Blob* blob);
-
-    /**
      * Adds a Confirmation Token to the key parameters if needed.
      */
     void appendConfirmationTokenIfNeeded(const KeyCharacteristics& keyCharacteristics,
                                          std::vector<KeyParameter>* params);
 
-    KeyStore* mKeyStore;
-    OperationMap mOperationMap;
-    android::sp<ConfirmationManager> mConfirmationManager;
-    keystore::AuthTokenTable mAuthTokenTable;
-    KeystoreKeymasterEnforcement enforcement_policy;
+    sp<KeyStore> mKeyStore;
+
+    std::mutex operationDeviceMapMutex_;
+    std::map<sp<IBinder>, std::shared_ptr<KeymasterWorker>> operationDeviceMap_;
+
+    void addOperationDevice(sp<IBinder> token, std::shared_ptr<KeymasterWorker> dev) {
+        std::lock_guard<std::mutex> lock(operationDeviceMapMutex_);
+        operationDeviceMap_.emplace(std::move(token), std::move(dev));
+    }
+    std::shared_ptr<KeymasterWorker> getOperationDevice(const sp<IBinder>& token) {
+        std::lock_guard<std::mutex> lock(operationDeviceMapMutex_);
+        auto it = operationDeviceMap_.find(token);
+        if (it != operationDeviceMap_.end()) {
+            return it->second;
+        }
+        return {};
+    }
+    void removeOperationDevice(const sp<IBinder>& token) {
+        std::lock_guard<std::mutex> lock(operationDeviceMapMutex_);
+        operationDeviceMap_.erase(token);
+    }
 };
 
 };  // namespace keystore
diff --git a/keystore/keymaster_enforcement.cpp b/keystore/keymaster_enforcement.cpp
index 1a7fa80..a17cd94 100644
--- a/keystore/keymaster_enforcement.cpp
+++ b/keystore/keymaster_enforcement.cpp
@@ -34,49 +34,6 @@
 
 namespace keystore {
 
-class AccessTimeMap {
-  public:
-    explicit AccessTimeMap(uint32_t max_size) : max_size_(max_size) {}
-
-    /* If the key is found, returns true and fills \p last_access_time.  If not found returns
-     * false. */
-    bool LastKeyAccessTime(km_id_t keyid, uint32_t* last_access_time) const;
-
-    /* Updates the last key access time with the currentTime parameter.  Adds the key if
-     * needed, returning false if key cannot be added because list is full. */
-    bool UpdateKeyAccessTime(km_id_t keyid, uint32_t current_time, uint32_t timeout);
-
-  private:
-    struct AccessTime {
-        km_id_t keyid;
-        uint32_t access_time;
-        uint32_t timeout;
-    };
-    std::list<AccessTime> last_access_list_;
-    const uint32_t max_size_;
-};
-
-class AccessCountMap {
-  public:
-    explicit AccessCountMap(uint32_t max_size) : max_size_(max_size) {}
-
-    /* If the key is found, returns true and fills \p count.  If not found returns
-     * false. */
-    bool KeyAccessCount(km_id_t keyid, uint32_t* count) const;
-
-    /* Increments key access count, adding an entry if the key has never been used.  Returns
-     * false if the list has reached maximum size. */
-    bool IncrementKeyAccessCount(km_id_t keyid);
-
-  private:
-    struct AccessCount {
-        km_id_t keyid;
-        uint64_t access_count;
-    };
-    std::list<AccessCount> access_count_list_;
-    const uint32_t max_size_;
-};
-
 bool is_public_key_algorithm(const AuthorizationSet& auth_set) {
     auto algorithm = auth_set.GetTagValue(TAG_ALGORITHM);
     return algorithm.isOk() &&
@@ -107,12 +64,9 @@
 
 KeymasterEnforcement::KeymasterEnforcement(uint32_t max_access_time_map_size,
                                            uint32_t max_access_count_map_size)
-    : access_time_map_(new (std::nothrow) AccessTimeMap(max_access_time_map_size)),
-      access_count_map_(new (std::nothrow) AccessCountMap(max_access_count_map_size)) {}
+    : access_time_map_(max_access_time_map_size), access_count_map_(max_access_count_map_size) {}
 
 KeymasterEnforcement::~KeymasterEnforcement() {
-    delete access_time_map_;
-    delete access_count_map_;
 }
 
 ErrorCode KeymasterEnforcement::AuthorizeOperation(const KeyPurpose purpose, const km_id_t keyid,
@@ -390,24 +344,14 @@
         return ErrorCode::CALLER_NONCE_PROHIBITED;
 
     if (min_ops_timeout != UINT32_MAX) {
-        if (!access_time_map_) {
-            ALOGE("Rate-limited keys table not allocated.  Rate-limited keys disabled");
-            return ErrorCode::MEMORY_ALLOCATION_FAILED;
-        }
-
-        if (!access_time_map_->UpdateKeyAccessTime(keyid, get_current_time(), min_ops_timeout)) {
+        if (!access_time_map_.UpdateKeyAccessTime(keyid, get_current_time(), min_ops_timeout)) {
             ALOGE("Rate-limited keys table full.  Entries will time out.");
             return ErrorCode::TOO_MANY_OPERATIONS;
         }
     }
 
     if (update_access_count) {
-        if (!access_count_map_) {
-            ALOGE("Usage-count limited keys tabel not allocated.  Count-limited keys disabled");
-            return ErrorCode::MEMORY_ALLOCATION_FAILED;
-        }
-
-        if (!access_count_map_->IncrementKeyAccessCount(keyid)) {
+        if (!access_count_map_.IncrementKeyAccessCount(keyid)) {
             ALOGE("Usage count-limited keys table full, until reboot.");
             return ErrorCode::TOO_MANY_OPERATIONS;
         }
@@ -428,35 +372,32 @@
 };
 
 /* static */
-bool KeymasterEnforcement::CreateKeyId(const hidl_vec<uint8_t>& key_blob, km_id_t* keyid) {
+std::optional<km_id_t> KeymasterEnforcement::CreateKeyId(const hidl_vec<uint8_t>& key_blob) {
     EvpMdCtx ctx;
+    km_id_t keyid;
 
     uint8_t hash[EVP_MAX_MD_SIZE];
     unsigned int hash_len;
     if (EVP_DigestInit_ex(ctx.get(), EVP_sha256(), nullptr /* ENGINE */) &&
         EVP_DigestUpdate(ctx.get(), &key_blob[0], key_blob.size()) &&
         EVP_DigestFinal_ex(ctx.get(), hash, &hash_len)) {
-        assert(hash_len >= sizeof(*keyid));
-        memcpy(keyid, hash, sizeof(*keyid));
-        return true;
+        assert(hash_len >= sizeof(keyid));
+        memcpy(&keyid, hash, sizeof(keyid));
+        return keyid;
     }
 
-    return false;
+    return {};
 }
 
 bool KeymasterEnforcement::MinTimeBetweenOpsPassed(uint32_t min_time_between, const km_id_t keyid) {
-    if (!access_time_map_) return false;
-
     uint32_t last_access_time;
-    if (!access_time_map_->LastKeyAccessTime(keyid, &last_access_time)) return true;
+    if (!access_time_map_.LastKeyAccessTime(keyid, &last_access_time)) return true;
     return min_time_between <= static_cast<int64_t>(get_current_time()) - last_access_time;
 }
 
 bool KeymasterEnforcement::MaxUsesPerBootNotExceeded(const km_id_t keyid, uint32_t max_uses) {
-    if (!access_count_map_) return false;
-
     uint32_t key_access_count;
-    if (!access_count_map_->KeyAccessCount(keyid, &key_access_count)) return true;
+    if (!access_count_map_.KeyAccessCount(keyid, &key_access_count)) return true;
     return key_access_count < max_uses;
 }
 
@@ -545,6 +486,7 @@
 }
 
 bool AccessTimeMap::LastKeyAccessTime(km_id_t keyid, uint32_t* last_access_time) const {
+    std::lock_guard<std::mutex> lock(list_lock_);
     for (auto& entry : last_access_list_)
         if (entry.keyid == keyid) {
             *last_access_time = entry.access_time;
@@ -554,6 +496,7 @@
 }
 
 bool AccessTimeMap::UpdateKeyAccessTime(km_id_t keyid, uint32_t current_time, uint32_t timeout) {
+    std::lock_guard<std::mutex> lock(list_lock_);
     for (auto iter = last_access_list_.begin(); iter != last_access_list_.end();) {
         if (iter->keyid == keyid) {
             iter->access_time = current_time;
@@ -579,6 +522,7 @@
 }
 
 bool AccessCountMap::KeyAccessCount(km_id_t keyid, uint32_t* count) const {
+    std::lock_guard<std::mutex> lock(list_lock_);
     for (auto& entry : access_count_list_)
         if (entry.keyid == keyid) {
             *count = entry.access_count;
@@ -588,6 +532,7 @@
 }
 
 bool AccessCountMap::IncrementKeyAccessCount(km_id_t keyid) {
+    std::lock_guard<std::mutex> lock(list_lock_);
     for (auto& entry : access_count_list_)
         if (entry.keyid == keyid) {
             // Note that the 'if' below will always be true because KM_TAG_MAX_USES_PER_BOOT is a
diff --git a/keystore/keymaster_enforcement.h b/keystore/keymaster_enforcement.h
index 6e6c54f..9bfb225 100644
--- a/keystore/keymaster_enforcement.h
+++ b/keystore/keymaster_enforcement.h
@@ -21,6 +21,10 @@
 
 #include <keystore/keymaster_types.h>
 
+#include <list>
+#include <mutex>
+#include <optional>
+
 namespace keystore {
 
 typedef uint64_t km_id_t;
@@ -33,8 +37,50 @@
      */
 };
 
-class AccessTimeMap;
-class AccessCountMap;
+class AccessTimeMap {
+  public:
+    explicit AccessTimeMap(uint32_t max_size) : max_size_(max_size) {}
+
+    /* If the key is found, returns true and fills \p last_access_time.  If not found returns
+     * false. */
+    bool LastKeyAccessTime(km_id_t keyid, uint32_t* last_access_time) const;
+
+    /* Updates the last key access time with the currentTime parameter.  Adds the key if
+     * needed, returning false if key cannot be added because list is full. */
+    bool UpdateKeyAccessTime(km_id_t keyid, uint32_t current_time, uint32_t timeout);
+
+  private:
+    mutable std::mutex list_lock_;
+    struct AccessTime {
+        km_id_t keyid;
+        uint32_t access_time;
+        uint32_t timeout;
+    };
+    std::list<AccessTime> last_access_list_;
+    const uint32_t max_size_;
+};
+
+class AccessCountMap {
+  public:
+    explicit AccessCountMap(uint32_t max_size) : max_size_(max_size) {}
+
+    /* If the key is found, returns true and fills \p count.  If not found returns
+     * false. */
+    bool KeyAccessCount(km_id_t keyid, uint32_t* count) const;
+
+    /* Increments key access count, adding an entry if the key has never been used.  Returns
+     * false if the list has reached maximum size. */
+    bool IncrementKeyAccessCount(km_id_t keyid);
+
+  private:
+    mutable std::mutex list_lock_;
+    struct AccessCount {
+        km_id_t keyid;
+        uint64_t access_count;
+    };
+    std::list<AccessCount> access_count_list_;
+    const uint32_t max_size_;
+};
 
 class KeymasterEnforcement {
   public:
@@ -92,7 +138,7 @@
      *
      * Returns false if an error in the crypto library prevents creation of an ID.
      */
-    static bool CreateKeyId(const hidl_vec<uint8_t>& key_blob, km_id_t* keyid);
+    static std::optional<km_id_t> CreateKeyId(const hidl_vec<uint8_t>& key_blob);
 
     //
     // Methods that must be implemented by subclasses
@@ -158,8 +204,8 @@
                           const int auth_timeout_index, const uint64_t op_handle,
                           bool is_begin_operation) const;
 
-    AccessTimeMap* access_time_map_;
-    AccessCountMap* access_count_map_;
+    AccessTimeMap access_time_map_;
+    AccessCountMap access_count_map_;
 };
 
 }; /* namespace keystore */
diff --git a/keystore/keymaster_worker.cpp b/keystore/keymaster_worker.cpp
new file mode 100644
index 0000000..1002b8d
--- /dev/null
+++ b/keystore/keymaster_worker.cpp
@@ -0,0 +1,1074 @@
+/*
+**
+** Copyright 2018, 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 "keymaster_worker"
+
+#include "keymaster_worker.h"
+
+#include "keystore_utils.h"
+
+#include <android-base/logging.h>
+
+#include "KeyStore.h"
+#include "keymaster_enforcement.h"
+
+#include "key_proto_handler.h"
+#include "keystore_utils.h"
+
+namespace keystore {
+
+constexpr size_t kMaxOperations = 15;
+
+using AndroidKeymasterArguments = android::security::keymaster::KeymasterArguments;
+using android::security::keymaster::ExportResult;
+using android::security::keymaster::operationFailed;
+using android::security::keymaster::OperationResult;
+
+Worker::Worker() {
+    worker_ = std::thread([this] {
+        std::unique_lock<std::mutex> lock(pending_requests_mutex_);
+        running_ = true;
+        while (running_) {
+            pending_requests_cond_var_.wait(
+                lock, [this]() { return !pending_requests_.empty() || !running_; });
+            if (!running_) break;
+            auto request = std::move(pending_requests_.front());
+            pending_requests_.pop();
+            lock.unlock();
+            request();
+            lock.lock();
+        }
+    });
+}
+Worker::~Worker() {
+    if (worker_.joinable()) {
+        running_ = false;
+        pending_requests_cond_var_.notify_all();
+        worker_.join();
+    }
+}
+void Worker::addRequest(WorkerTask request) {
+    std::unique_lock<std::mutex> lock(pending_requests_mutex_);
+    pending_requests_.push(std::move(request));
+    lock.unlock();
+    pending_requests_cond_var_.notify_all();
+}
+
+KeymasterWorker::KeymasterWorker(sp<Keymaster> keymasterDevice, KeyStore* keyStore)
+    : keymasterDevice_(std::move(keymasterDevice)), operationMap_(keyStore), keyStore_(keyStore) {
+    // make sure that hal version is cached.
+    if (keymasterDevice_) keymasterDevice_->halVersion();
+}
+
+std::tuple<KeyStoreServiceReturnCode, Blob>
+KeymasterWorker::upgradeKeyBlob(const LockedKeyBlobEntry& lockedEntry,
+                                const AuthorizationSet& params) {
+    LOG(INFO) << "upgradeKeyBlob " << lockedEntry->alias() << " " << (uint32_t)lockedEntry->uid();
+
+    std::tuple<KeyStoreServiceReturnCode, Blob> result;
+
+    auto userState = keyStore_->getUserStateDB().getUserStateByUid(lockedEntry->uid());
+
+    Blob& blob = std::get<1>(result);
+    KeyStoreServiceReturnCode& error = std::get<0>(result);
+
+    Blob charBlob;
+    ResponseCode rc;
+
+    std::tie(rc, blob, charBlob) =
+        lockedEntry.readBlobs(userState->getEncryptionKey(), userState->getState());
+
+    if (rc != ResponseCode::NO_ERROR) {
+        return error = rc, result;
+    }
+
+    auto hidlKey = blob2hidlVec(blob);
+    auto& dev = keymasterDevice_;
+
+    auto hidlCb = [&](ErrorCode ret, const ::std::vector<uint8_t>& upgradedKeyBlob) {
+        error = ret;
+        if (!error.isOk()) {
+            if (error == ErrorCode::INVALID_KEY_BLOB) {
+                log_key_integrity_violation(lockedEntry->alias().c_str(), lockedEntry->uid());
+            }
+            return;
+        }
+
+        error = keyStore_->del(lockedEntry);
+        if (!error.isOk()) {
+            ALOGI("upgradeKeyBlob keystore->del failed %d", (int)error);
+            return;
+        }
+
+        Blob newBlob(&upgradedKeyBlob[0], upgradedKeyBlob.size(), nullptr /* info */,
+                     0 /* infoLength */, ::TYPE_KEYMASTER_10);
+        newBlob.setSecurityLevel(blob.getSecurityLevel());
+        newBlob.setEncrypted(blob.isEncrypted());
+        newBlob.setSuperEncrypted(blob.isSuperEncrypted());
+        newBlob.setCriticalToDeviceEncryption(blob.isCriticalToDeviceEncryption());
+
+        error = keyStore_->put(lockedEntry, newBlob, charBlob);
+        if (!error.isOk()) {
+            ALOGI("upgradeKeyBlob keystore->put failed %d", (int)error);
+            return;
+        }
+        blob = std::move(newBlob);
+    };
+
+    KeyStoreServiceReturnCode error2;
+    error2 = KS_HANDLE_HIDL_ERROR(dev->upgradeKey(hidlKey, params.hidl_data(), hidlCb));
+    if (!error2.isOk()) {
+        return error = error2, result;
+    }
+
+    return result;
+}
+
+std::tuple<KeyStoreServiceReturnCode, KeyCharacteristics, Blob, Blob>
+KeymasterWorker::createKeyCharacteristicsCache(const LockedKeyBlobEntry& lockedEntry,
+                                               const hidl_vec<uint8_t>& clientId,
+                                               const hidl_vec<uint8_t>& appData, Blob keyBlob,
+                                               Blob charBlob) {
+    std::tuple<KeyStoreServiceReturnCode, KeyCharacteristics, Blob, Blob> result;
+
+#if __cplusplus == 201703L
+    auto& [rc, resultCharacteristics, outBlob, charOutBlob] = result;
+#else
+    KeyStoreServiceReturnCode& rc = std::get<0>(result);
+    KeyCharacteristics& resultCharacteristics = std::get<1>(result);
+    Blob& outBlob = std::get<2>(result);
+    Blob& charOutBlob = std::get<3>(result);
+#endif
+
+    rc = ResponseCode::SYSTEM_ERROR;
+    if (!keyBlob) return result;
+    auto hidlKeyBlob = blob2hidlVec(keyBlob);
+    auto& dev = keymasterDevice_;
+
+    KeyStoreServiceReturnCode error;
+
+    AuthorizationSet hwEnforced, swEnforced;
+    bool success = true;
+
+    if (charBlob) {
+        std::tie(success, hwEnforced, swEnforced) = charBlob.getKeyCharacteristics();
+    }
+    if (!success) {
+        LOG(ERROR) << "Failed to read cached key characteristics";
+        return rc = ResponseCode::SYSTEM_ERROR, result;
+    }
+
+    auto hidlCb = [&](ErrorCode ret, const KeyCharacteristics& keyCharacteristics) {
+        error = ret;
+        if (!error.isOk()) {
+            if (error == ErrorCode::INVALID_KEY_BLOB) {
+                log_key_integrity_violation(lockedEntry->alias().c_str(), lockedEntry->uid());
+            }
+            return;
+        }
+
+        // Replace the sw_enforced set with those persisted to disk, minus hw_enforced
+        AuthorizationSet softwareEnforced = keyCharacteristics.softwareEnforced;
+        hwEnforced = keyCharacteristics.hardwareEnforced;
+        swEnforced.Union(softwareEnforced);
+        softwareEnforced.Subtract(hwEnforced);
+
+        // We only get the characteristics from keymaster if there was no cache file or the
+        // the chach file was a legacy cache file. So lets write a new cache file for the next time.
+        Blob newCharBlob;
+        success = newCharBlob.putKeyCharacteristics(hwEnforced, swEnforced);
+        if (!success) {
+            error = ResponseCode::SYSTEM_ERROR;
+            LOG(ERROR) << "Failed to serialize cached key characteristics";
+            return;
+        }
+
+        error = keyStore_->put(lockedEntry, {}, newCharBlob);
+        if (!error.isOk()) {
+            ALOGE("Failed to write key characteristics cache");
+            return;
+        }
+        charBlob = std::move(newCharBlob);
+    };
+
+    if (!charBlob || charBlob.getType() == TYPE_KEY_CHARACTERISTICS) {
+        // this updates the key characteristics cache file to the new format or creates one in
+        // in the first place
+        rc = KS_HANDLE_HIDL_ERROR(
+            dev->getKeyCharacteristics(hidlKeyBlob, clientId, appData, hidlCb));
+        if (!rc.isOk()) {
+            return result;
+        }
+
+        if (error == ErrorCode::KEY_REQUIRES_UPGRADE) {
+            AuthorizationSet upgradeParams;
+            if (clientId.size()) {
+                upgradeParams.push_back(TAG_APPLICATION_ID, clientId);
+            }
+            if (appData.size()) {
+                upgradeParams.push_back(TAG_APPLICATION_DATA, appData);
+            }
+            std::tie(rc, keyBlob) = upgradeKeyBlob(lockedEntry, upgradeParams);
+            if (!rc.isOk()) {
+                return result;
+            }
+
+            auto upgradedHidlKeyBlob = blob2hidlVec(keyBlob);
+
+            rc = KS_HANDLE_HIDL_ERROR(
+                dev->getKeyCharacteristics(upgradedHidlKeyBlob, clientId, appData, hidlCb));
+            if (!rc.isOk()) {
+                return result;
+            }
+        }
+    }
+
+    resultCharacteristics.hardwareEnforced = hwEnforced.hidl_data();
+    resultCharacteristics.softwareEnforced = swEnforced.hidl_data();
+
+    outBlob = std::move(keyBlob);
+    charOutBlob = std::move(charBlob);
+    rc = error;
+    return result;
+}
+
+/**
+ * Get the auth token for this operation from the auth token table.
+ *
+ * Returns ResponseCode::NO_ERROR if the auth token was set or none was required.
+ *         ::OP_AUTH_NEEDED if it is a per op authorization, no
+ *         authorization token exists for that operation and
+ *         failOnTokenMissing is false.
+ *         KM_ERROR_KEY_USER_NOT_AUTHENTICATED if there is no valid auth
+ *         token for the operation
+ */
+std::pair<KeyStoreServiceReturnCode, HardwareAuthToken>
+KeymasterWorker::getAuthToken(const KeyCharacteristics& characteristics, uint64_t handle,
+                              KeyPurpose purpose, bool failOnTokenMissing) {
+
+    AuthorizationSet allCharacteristics(characteristics.softwareEnforced);
+    allCharacteristics.append(characteristics.hardwareEnforced.begin(),
+                              characteristics.hardwareEnforced.end());
+
+    HardwareAuthToken authToken;
+    AuthTokenTable::Error err;
+    std::tie(err, authToken) = keyStore_->getAuthTokenTable().FindAuthorization(
+        allCharacteristics, static_cast<KeyPurpose>(purpose), handle);
+
+    KeyStoreServiceReturnCode rc;
+
+    switch (err) {
+    case AuthTokenTable::OK:
+    case AuthTokenTable::AUTH_NOT_REQUIRED:
+        rc = ResponseCode::NO_ERROR;
+        break;
+
+    case AuthTokenTable::AUTH_TOKEN_NOT_FOUND:
+    case AuthTokenTable::AUTH_TOKEN_EXPIRED:
+    case AuthTokenTable::AUTH_TOKEN_WRONG_SID:
+        ALOGE("getAuthToken failed: %d", err);  // STOPSHIP: debug only, to be removed
+        rc = ErrorCode::KEY_USER_NOT_AUTHENTICATED;
+        break;
+
+    case AuthTokenTable::OP_HANDLE_REQUIRED:
+        rc = failOnTokenMissing ? KeyStoreServiceReturnCode(ErrorCode::KEY_USER_NOT_AUTHENTICATED)
+                                : KeyStoreServiceReturnCode(ResponseCode::OP_AUTH_NEEDED);
+        break;
+
+    default:
+        ALOGE("Unexpected FindAuthorization return value %d", err);
+        rc = ErrorCode::INVALID_ARGUMENT;
+    }
+
+    return {rc, std::move(authToken)};
+}
+
+KeyStoreServiceReturnCode KeymasterWorker::abort(const sp<IBinder>& token) {
+    auto op = operationMap_.removeOperation(token, false /* wasOpSuccessful */);
+    if (op) {
+        keyStore_->getAuthTokenTable().MarkCompleted(op->handle);
+        return KS_HANDLE_HIDL_ERROR(keymasterDevice_->abort(op->handle));
+    } else {
+        return ErrorCode::INVALID_OPERATION_HANDLE;
+    }
+}
+
+/**
+ * Prune the oldest pruneable operation.
+ */
+bool KeymasterWorker::pruneOperation() {
+    sp<IBinder> oldest = operationMap_.getOldestPruneableOperation();
+    ALOGD("Trying to prune operation %p", oldest.get());
+    size_t op_count_before_abort = operationMap_.getOperationCount();
+    // We mostly ignore errors from abort() because all we care about is whether at least
+    // one operation has been removed.
+    auto rc = abort(oldest);
+    if (operationMap_.getOperationCount() >= op_count_before_abort) {
+        ALOGE("Failed to abort pruneable operation %p, error: %d", oldest.get(), int32_t(rc));
+        return false;
+    }
+    return true;
+}
+
+// My IDE defines "CAPTURE_MOVE(x) x" because it does not understand generalized lambda captures.
+// It should never be redefined by a build system though.
+#ifndef CAPTURE_MOVE
+#define CAPTURE_MOVE(x) x = std::move(x)
+#endif
+
+void KeymasterWorker::begin(LockedKeyBlobEntry lockedEntry, sp<IBinder> appToken, Blob keyBlob,
+                            Blob charBlob, bool pruneable, KeyPurpose purpose,
+                            AuthorizationSet opParams, hidl_vec<uint8_t> entropy,
+                            worker_begin_cb worker_cb) {
+
+    Worker::addRequest([this, CAPTURE_MOVE(lockedEntry), CAPTURE_MOVE(appToken),
+                        CAPTURE_MOVE(keyBlob), CAPTURE_MOVE(charBlob), pruneable, purpose,
+                        CAPTURE_MOVE(opParams), CAPTURE_MOVE(entropy),
+                        CAPTURE_MOVE(worker_cb)]() mutable {
+        // Concurrently executed
+
+        auto key = blob2hidlVec(keyBlob);
+        auto& dev = keymasterDevice_;
+
+        KeyCharacteristics characteristics;
+
+        {
+            hidl_vec<uint8_t> clientId;
+            hidl_vec<uint8_t> appData;
+            for (auto param : opParams) {
+                if (param.tag == Tag::APPLICATION_ID) {
+                    clientId = authorizationValue(TAG_APPLICATION_ID, param).value();
+                } else if (param.tag == Tag::APPLICATION_DATA) {
+                    appData = authorizationValue(TAG_APPLICATION_DATA, param).value();
+                }
+            }
+            KeyStoreServiceReturnCode error;
+            std::tie(error, characteristics, keyBlob, charBlob) = createKeyCharacteristicsCache(
+                lockedEntry, clientId, appData, std::move(keyBlob), std::move(charBlob));
+            if (!error.isOk()) {
+                worker_cb(operationFailed(error));
+                return;
+            }
+        }
+
+        KeyStoreServiceReturnCode rc, authRc;
+        HardwareAuthToken authToken;
+        std::tie(authRc, authToken) = getAuthToken(characteristics, 0 /* no challenge */, purpose,
+                                                   /*failOnTokenMissing*/ false);
+
+        // If per-operation auth is needed we need to begin the operation and
+        // the client will need to authorize that operation before calling
+        // update. Any other auth issues stop here.
+        if (!authRc.isOk() && authRc != ResponseCode::OP_AUTH_NEEDED) {
+            return worker_cb(operationFailed(authRc));
+        }
+
+        // Add entropy to the device first.
+        if (entropy.size()) {
+            rc = KS_HANDLE_HIDL_ERROR(dev->addRngEntropy(entropy));
+            if (!rc.isOk()) {
+                return worker_cb(operationFailed(rc));
+            }
+        }
+
+        // Create a keyid for this key.
+        auto keyid = KeymasterEnforcement::CreateKeyId(key);
+        if (!keyid) {
+            ALOGE("Failed to create a key ID for authorization checking.");
+            return worker_cb(operationFailed(ErrorCode::UNKNOWN_ERROR));
+        }
+
+        // Check that all key authorization policy requirements are met.
+        AuthorizationSet key_auths = characteristics.hardwareEnforced;
+        key_auths.append(characteristics.softwareEnforced.begin(),
+                         characteristics.softwareEnforced.end());
+
+        rc = keyStore_->getEnforcementPolicy().AuthorizeOperation(
+            purpose, *keyid, key_auths, opParams, authToken, 0 /* op_handle */,
+            true /* is_begin_operation */);
+        if (!rc.isOk()) {
+            return worker_cb(operationFailed(rc));
+        }
+
+        // If there are more than kMaxOperations, abort the oldest operation that was started as
+        // pruneable.
+        while (operationMap_.getOperationCount() >= kMaxOperations) {
+            ALOGD("Reached or exceeded concurrent operations limit");
+            if (!pruneOperation()) {
+                break;
+            }
+        }
+
+        android::security::keymaster::OperationResult result;
+
+        auto hidlCb = [&](ErrorCode ret, const hidl_vec<KeyParameter>& outParams,
+                          uint64_t operationHandle) {
+            result.resultCode = ret;
+            if (!result.resultCode.isOk()) {
+                if (result.resultCode == ErrorCode::INVALID_KEY_BLOB) {
+                    log_key_integrity_violation(lockedEntry->alias().c_str(), lockedEntry->uid());
+                }
+                return;
+            }
+            result.handle = operationHandle;
+            result.outParams = outParams;
+        };
+
+        do {
+            rc = KS_HANDLE_HIDL_ERROR(
+                dev->begin(purpose, key, opParams.hidl_data(), authToken, hidlCb));
+            if (!rc.isOk()) {
+                LOG(ERROR) << "Got error " << rc << " from begin()";
+                return worker_cb(operationFailed(ResponseCode::SYSTEM_ERROR));
+            }
+            // If there are too many operations abort the oldest operation that was
+            // started as pruneable and try again.
+        } while (result.resultCode == ErrorCode::TOO_MANY_OPERATIONS && pruneOperation());
+
+        rc = result.resultCode;
+        if (!rc.isOk()) {
+            return worker_cb(operationFailed(rc));
+        }
+
+        // Note: The operation map takes possession of the contents of "characteristics".
+        // It is safe to use characteristics after the following line but it will be empty.
+        sp<IBinder> operationToken =
+            operationMap_.addOperation(result.handle, *keyid, purpose, dev, appToken,
+                                       std::move(characteristics), opParams.hidl_data(), pruneable);
+        assert(characteristics.hardwareEnforced.size() == 0);
+        assert(characteristics.softwareEnforced.size() == 0);
+        result.token = operationToken;
+
+        auto operation = operationMap_.getOperation(operationToken);
+        if (!operation) {
+            return worker_cb(operationFailed(ResponseCode::SYSTEM_ERROR));
+        }
+
+        if (authRc.isOk() && authToken.mac.size() &&
+            dev->halVersion().securityLevel == SecurityLevel::STRONGBOX) {
+            operation->authTokenFuture = operation->authTokenPromise.get_future();
+            std::weak_ptr<Operation> weak_operation = operation;
+
+            auto verifyTokenCB = [weak_operation](KeyStoreServiceReturnCode rc,
+                                                  HardwareAuthToken authToken,
+                                                  VerificationToken verificationToken) {
+                auto operation = weak_operation.lock();
+                if (!operation) {
+                    // operation aborted, nothing to do
+                    return;
+                }
+                if (rc.isOk()) {
+                    operation->authToken = std::move(authToken);
+                    operation->verificationToken = std::move(verificationToken);
+                }
+                operation->authTokenPromise.set_value(rc);
+            };
+            auto teeKmDevice = keyStore_->getDevice(SecurityLevel::TRUSTED_ENVIRONMENT);
+            teeKmDevice->verifyAuthorization(result.handle, {}, std::move(authToken),
+                                             std::move(verifyTokenCB));
+        }
+
+        // Return the authentication lookup result. If this is a per operation
+        // auth'd key then the resultCode will be ::OP_AUTH_NEEDED and the
+        // application should get an auth token using the handle before the
+        // first call to update, which will fail if keystore hasn't received the
+        // auth token.
+        if (result.resultCode.isOk()) {
+            result.resultCode = authRc;
+        }
+        return worker_cb(result);
+    });
+}
+
+KeyStoreServiceReturnCode
+KeymasterWorker::getOperationAuthTokenIfNeeded(std::shared_ptr<Operation> op) {
+    if (!op) return ErrorCode::INVALID_OPERATION_HANDLE;
+
+    if (op->authTokenFuture.valid()) {
+        LOG(INFO) << "Waiting for verification token";
+        op->authTokenFuture.wait();
+        auto rc = op->authTokenFuture.get();
+        if (!rc.isOk()) {
+            return rc;
+        }
+        op->authTokenFuture = {};
+    } else if (!op->hasAuthToken()) {
+        KeyStoreServiceReturnCode rc;
+        HardwareAuthToken found;
+        std::tie(rc, found) = getAuthToken(op->characteristics, op->handle, op->purpose);
+        if (!rc.isOk()) return rc;
+        op->authToken = std::move(found);
+    }
+
+    return ResponseCode::NO_ERROR;
+}
+
+namespace {
+
+class Finalize {
+  private:
+    std::function<void()> f_;
+
+  public:
+    Finalize(std::function<void()> f) : f_(f) {}
+    ~Finalize() {
+        if (f_) f_();
+    }
+    void release() { f_ = {}; }
+};
+
+}  // namespace
+
+void KeymasterWorker::update(sp<IBinder> token, AuthorizationSet params, hidl_vec<uint8_t> data,
+                             update_cb worker_cb) {
+    Worker::addRequest([this, CAPTURE_MOVE(token), CAPTURE_MOVE(params), CAPTURE_MOVE(data),
+                        CAPTURE_MOVE(worker_cb)]() {
+        KeyStoreServiceReturnCode rc;
+        auto op = operationMap_.getOperation(token);
+        if (!op) {
+            return worker_cb(operationFailed(ErrorCode::INVALID_OPERATION_HANDLE));
+        }
+
+        Finalize abort_operation_in_case_of_error([&] {
+            operationMap_.removeOperation(token, false);
+            keyStore_->getAuthTokenTable().MarkCompleted(op->handle);
+            KS_HANDLE_HIDL_ERROR(keymasterDevice_->abort(op->handle));
+        });
+
+        rc = getOperationAuthTokenIfNeeded(op);
+        if (!rc.isOk()) return worker_cb(operationFailed(rc));
+
+        // Check that all key authorization policy requirements are met.
+        AuthorizationSet key_auths(op->characteristics.hardwareEnforced);
+        key_auths.append(op->characteristics.softwareEnforced.begin(),
+                         op->characteristics.softwareEnforced.end());
+
+        rc = keyStore_->getEnforcementPolicy().AuthorizeOperation(op->purpose, op->keyid, key_auths,
+                                                                  params, op->authToken, op->handle,
+                                                                  false /* is_begin_operation */);
+        if (!rc.isOk()) return worker_cb(operationFailed(rc));
+
+        OperationResult result;
+        auto hidlCb = [&](ErrorCode ret, uint32_t inputConsumed,
+                          const hidl_vec<KeyParameter>& outParams,
+                          const ::std::vector<uint8_t>& output) {
+            result.resultCode = ret;
+            if (result.resultCode.isOk()) {
+                result.inputConsumed = inputConsumed;
+                result.outParams = outParams;
+                result.data = output;
+            }
+        };
+
+        rc = KS_HANDLE_HIDL_ERROR(op->device->update(op->handle, params.hidl_data(), data,
+                                                     op->authToken, op->verificationToken, hidlCb));
+
+        // just a reminder: on success result->resultCode was set in the callback. So we only
+        // overwrite it if there was a communication error indicated by the ErrorCode.
+        if (!rc.isOk()) result.resultCode = rc;
+        if (result.resultCode.isOk()) {
+            // if everything went well we don't abort the operation.
+            abort_operation_in_case_of_error.release();
+        }
+        return worker_cb(std::move(result));
+    });
+}
+
+/**
+ * Check that all KeyParameters provided by the application are allowed. Any parameter that keystore
+ * adds itself should be disallowed here.
+ */
+template <typename ParamsIter>
+static bool checkAllowedOperationParams(ParamsIter begin, const ParamsIter end) {
+    while (begin != end) {
+        switch (begin->tag) {
+        case Tag::ATTESTATION_APPLICATION_ID:
+        case Tag::RESET_SINCE_ID_ROTATION:
+            return false;
+        default:
+            break;
+        }
+        ++begin;
+    }
+    return true;
+}
+
+void KeymasterWorker::finish(sp<IBinder> token, AuthorizationSet params, hidl_vec<uint8_t> input,
+                             hidl_vec<uint8_t> signature, hidl_vec<uint8_t> entropy,
+                             finish_cb worker_cb) {
+    Worker::addRequest([this, CAPTURE_MOVE(token), CAPTURE_MOVE(params), CAPTURE_MOVE(input),
+                        CAPTURE_MOVE(signature), CAPTURE_MOVE(entropy),
+                        CAPTURE_MOVE(worker_cb)]() mutable {
+        KeyStoreServiceReturnCode rc;
+        auto op = operationMap_.getOperation(token);
+        if (!op) {
+            return worker_cb(operationFailed(ErrorCode::INVALID_OPERATION_HANDLE));
+        }
+
+        bool finished = false;
+        Finalize abort_operation_in_case_of_error([&] {
+            operationMap_.removeOperation(token, finished && rc.isOk());
+            keyStore_->getAuthTokenTable().MarkCompleted(op->handle);
+            if (!finished) KS_HANDLE_HIDL_ERROR(keymasterDevice_->abort(op->handle));
+        });
+
+        if (!checkAllowedOperationParams(params.begin(), params.end())) {
+            return worker_cb(operationFailed(ErrorCode::INVALID_ARGUMENT));
+        }
+
+        rc = getOperationAuthTokenIfNeeded(op);
+        if (!rc.isOk()) return worker_cb(operationFailed(rc));
+
+        // Check that all key authorization policy requirements are met.
+        AuthorizationSet key_auths(op->characteristics.hardwareEnforced);
+        key_auths.append(op->characteristics.softwareEnforced.begin(),
+                         op->characteristics.softwareEnforced.end());
+
+        if (key_auths.Contains(Tag::TRUSTED_CONFIRMATION_REQUIRED)) {
+            hidl_vec<uint8_t> confirmationToken =
+                keyStore_->getConfirmationManager().getLatestConfirmationToken();
+            if (confirmationToken.size() == 0) {
+                LOG(ERROR) << "Confirmation token required but none found";
+                return worker_cb(operationFailed(ErrorCode::NO_USER_CONFIRMATION));
+            }
+            params.push_back(keymaster::TAG_CONFIRMATION_TOKEN, std::move(confirmationToken));
+        }
+
+        rc = keyStore_->getEnforcementPolicy().AuthorizeOperation(op->purpose, op->keyid, key_auths,
+                                                                  params, op->authToken, op->handle,
+                                                                  false /* is_begin_operation */);
+        if (!rc.isOk()) return worker_cb(operationFailed(rc));
+
+        if (entropy.size()) {
+            rc = KS_HANDLE_HIDL_ERROR(op->device->addRngEntropy(entropy));
+            if (!rc.isOk()) {
+                return worker_cb(operationFailed(rc));
+            }
+        }
+
+        OperationResult result;
+        auto hidlCb = [&](ErrorCode ret, const hidl_vec<KeyParameter>& outParams,
+                          const ::std::vector<uint8_t>& output) {
+            result.resultCode = ret;
+            if (result.resultCode.isOk()) {
+                result.outParams = outParams;
+                result.data = output;
+            }
+        };
+
+        rc = KS_HANDLE_HIDL_ERROR(op->device->finish(op->handle, params.hidl_data(), input,
+                                                     signature, op->authToken,
+                                                     op->verificationToken, hidlCb));
+
+        if (rc.isOk()) {
+            // inform the finalizer that the finish call went through
+            finished = true;
+            // and what the result was
+            rc = result.resultCode;
+        } else {
+            return worker_cb(operationFailed(rc));
+        }
+        return worker_cb(std::move(result));
+    });
+}
+
+void KeymasterWorker::abort(sp<IBinder> token, abort_cb worker_cb) {
+    Worker::addRequest(
+        [this, CAPTURE_MOVE(token), CAPTURE_MOVE(worker_cb)]() { return worker_cb(abort(token)); });
+}
+
+void KeymasterWorker::verifyAuthorization(uint64_t challenge, hidl_vec<KeyParameter> params,
+                                          HardwareAuthToken token,
+                                          verifyAuthorization_cb worker_cb) {
+    Worker::addRequest([this, challenge, CAPTURE_MOVE(params), CAPTURE_MOVE(token),
+                        CAPTURE_MOVE(worker_cb)]() {
+        KeyStoreServiceReturnCode error;
+        VerificationToken verificationToken;
+        KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(keymasterDevice_->verifyAuthorization(
+            challenge, params, token, [&](ErrorCode error_, const VerificationToken& vToken) {
+                error = error_;
+                verificationToken = vToken;
+            }));
+        worker_cb(rc.isOk() ? error : rc, std::move(token), std::move(verificationToken));
+    });
+}
+
+void KeymasterWorker::addRngEntropy(hidl_vec<uint8_t> data, addRngEntropy_cb _hidl_cb) {
+    addRequest(&Keymaster::addRngEntropy, std::move(_hidl_cb), std::move(data));
+}
+
+namespace {
+bool containsTag(const hidl_vec<KeyParameter>& params, Tag tag) {
+    return params.end() !=
+           std::find_if(params.begin(), params.end(),
+                        [&](const KeyParameter& param) { return param.tag == tag; });
+}
+
+bool isAuthenticationBound(const hidl_vec<KeyParameter>& params) {
+    return !containsTag(params, Tag::NO_AUTH_REQUIRED);
+}
+}  // namespace
+
+void KeymasterWorker::generateKey(LockedKeyBlobEntry lockedEntry, hidl_vec<KeyParameter> keyParams,
+                                  hidl_vec<uint8_t> entropy, int flags, generateKey_cb worker_cb) {
+    Worker::addRequest([this, CAPTURE_MOVE(lockedEntry), CAPTURE_MOVE(keyParams),
+                        CAPTURE_MOVE(entropy), CAPTURE_MOVE(worker_cb), flags]() mutable {
+        KeyStoreServiceReturnCode rc =
+            KS_HANDLE_HIDL_ERROR(keymasterDevice_->addRngEntropy(entropy));
+        if (!rc.isOk()) {
+            return worker_cb(rc, {});
+        }
+
+        SecurityLevel securityLevel = keymasterDevice_->halVersion().securityLevel;
+
+        // Fallback cannot be considered for Strongbox. Further versions restrictions are enforced
+        // by KeyStore::getFallbackDevice()
+        bool consider_fallback = securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT;
+
+        Finalize logOnFail(
+            [&] { uploadKeyCharacteristicsAsProto(keyParams, false /* wasCreationSuccessful */); });
+
+        KeyCharacteristics outCharacteristics;
+        KeyStoreServiceReturnCode error;
+        auto hidl_cb = [&](ErrorCode ret, const hidl_vec<uint8_t>& hidlKeyBlob,
+                           const KeyCharacteristics& keyCharacteristics) {
+            error = ret;
+            if (!error.isOk()) {
+                return;
+            }
+            consider_fallback = false;
+            outCharacteristics = keyCharacteristics;
+
+            Blob keyBlob(&hidlKeyBlob[0], hidlKeyBlob.size(), nullptr, 0, ::TYPE_KEYMASTER_10);
+            keyBlob.setSecurityLevel(securityLevel);
+            keyBlob.setCriticalToDeviceEncryption(flags &
+                                                  KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
+            if (isAuthenticationBound(keyParams) && !keyBlob.isCriticalToDeviceEncryption()) {
+                keyBlob.setSuperEncrypted(true);
+            }
+            keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
+
+            AuthorizationSet sw_enforced = keyParams;
+            sw_enforced.Subtract(outCharacteristics.hardwareEnforced);
+            sw_enforced.Union(outCharacteristics.softwareEnforced);
+            sw_enforced.Filter([](const KeyParameter& param) -> bool {
+                return !(param.tag == Tag::APPLICATION_DATA || param.tag == Tag::APPLICATION_ID);
+            });
+            if (!sw_enforced.Contains(Tag::USER_ID)) {
+                // Most Java processes don't have access to this tag
+                sw_enforced.push_back(keymaster::TAG_USER_ID, get_user_id(lockedEntry->uid()));
+            }
+            Blob keyCharBlob;
+            keyCharBlob.putKeyCharacteristics(outCharacteristics.hardwareEnforced, sw_enforced);
+            error = keyStore_->put(lockedEntry, std::move(keyBlob), std::move(keyCharBlob));
+        };
+
+        rc = KS_HANDLE_HIDL_ERROR(keymasterDevice_->generateKey(keyParams, hidl_cb));
+        if (!rc.isOk()) {
+            return worker_cb(rc, {});
+        }
+
+        if (consider_fallback && !error.isOk()) {
+            auto fallback = keyStore_->getFallbackDevice();
+            if (!fallback) {
+                return worker_cb(error, {});
+            }
+            // No fallback for 3DES
+            for (auto& param : keyParams) {
+                auto algorithm = authorizationValue(TAG_ALGORITHM, param);
+                if (algorithm.isOk() && algorithm.value() == Algorithm::TRIPLE_DES) {
+                    return worker_cb(ErrorCode::UNSUPPORTED_ALGORITHM, {});
+                }
+            }
+
+            // delegate to fallback worker
+            fallback->generateKey(std::move(lockedEntry), std::move(keyParams), std::move(entropy),
+                                  flags, std::move(worker_cb));
+            // let fallback do the logging
+            logOnFail.release();
+            return;
+        }
+
+        if (!error.isOk()) return worker_cb(error, {});
+
+        // log on success
+        logOnFail.release();
+        uploadKeyCharacteristicsAsProto(keyParams, true /* wasCreationSuccessful */);
+
+        return worker_cb(error, std::move(outCharacteristics));
+    });
+}
+
+void KeymasterWorker::generateKey(hidl_vec<KeyParameter> keyParams, generateKey2_cb worker_cb) {
+    addRequest(&Keymaster::generateKey, std::move(worker_cb), std::move(keyParams));
+}
+
+void KeymasterWorker::getKeyCharacteristics(LockedKeyBlobEntry lockedEntry,
+                                            hidl_vec<uint8_t> clientId, hidl_vec<uint8_t> appData,
+                                            Blob keyBlob, Blob charBlob,
+                                            getKeyCharacteristics_cb worker_cb) {
+    Worker::addRequest([this, CAPTURE_MOVE(lockedEntry), CAPTURE_MOVE(clientId),
+                        CAPTURE_MOVE(appData), CAPTURE_MOVE(keyBlob), CAPTURE_MOVE(charBlob),
+                        CAPTURE_MOVE(worker_cb)]() {
+        auto result = createKeyCharacteristicsCache(lockedEntry, clientId, appData,
+                                                    std::move(keyBlob), std::move(charBlob));
+        return worker_cb(std::get<0>(result), std::move(std::get<1>(result)));
+    });
+}
+
+void KeymasterWorker::importKey(LockedKeyBlobEntry lockedEntry, hidl_vec<KeyParameter> keyParams,
+                                KeyFormat keyFormat, hidl_vec<uint8_t> keyData, int flags,
+                                importKey_cb worker_cb) {
+    Worker::addRequest([this, CAPTURE_MOVE(lockedEntry), CAPTURE_MOVE(keyParams), keyFormat,
+                        CAPTURE_MOVE(keyData), flags, CAPTURE_MOVE(worker_cb)]() mutable {
+        SecurityLevel securityLevel = keymasterDevice_->halVersion().securityLevel;
+
+        // Fallback cannot be considered for Strongbox. Further versions restrictions are enforced
+        // by KeyStore::getFallbackDevice()
+        bool consider_fallback = securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT;
+
+        Finalize logOnFail(
+            [&] { uploadKeyCharacteristicsAsProto(keyParams, false /* wasCreationSuccessful */); });
+
+        KeyCharacteristics outCharacteristics;
+        KeyStoreServiceReturnCode error;
+        auto hidl_cb = [&](ErrorCode ret, const hidl_vec<uint8_t>& hidlKeyBlob,
+                           const KeyCharacteristics& keyCharacteristics) {
+            error = ret;
+            if (!error.isOk()) {
+                LOG(INFO) << "importKey failed";
+                return;
+            }
+            consider_fallback = false;
+            outCharacteristics = keyCharacteristics;
+
+            Blob keyBlob(&hidlKeyBlob[0], hidlKeyBlob.size(), nullptr, 0, ::TYPE_KEYMASTER_10);
+            keyBlob.setSecurityLevel(securityLevel);
+            keyBlob.setCriticalToDeviceEncryption(flags &
+                                                  KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
+            if (isAuthenticationBound(keyParams) && !keyBlob.isCriticalToDeviceEncryption()) {
+                keyBlob.setSuperEncrypted(true);
+            }
+            keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
+
+            AuthorizationSet sw_enforced = keyParams;
+            sw_enforced.Subtract(outCharacteristics.hardwareEnforced);
+            sw_enforced.Union(outCharacteristics.softwareEnforced);
+            sw_enforced.Filter([](const KeyParameter& param) -> bool {
+                return !(param.tag == Tag::APPLICATION_DATA || param.tag == Tag::APPLICATION_ID);
+            });
+            if (!sw_enforced.Contains(Tag::USER_ID)) {
+                // Most Java processes don't have access to this tag
+                sw_enforced.push_back(keymaster::TAG_USER_ID, get_user_id(lockedEntry->uid()));
+            }
+            Blob keyCharBlob;
+            keyCharBlob.putKeyCharacteristics(outCharacteristics.hardwareEnforced, sw_enforced);
+            error = keyStore_->put(lockedEntry, std::move(keyBlob), std::move(keyCharBlob));
+        };
+
+        KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(
+            keymasterDevice_->importKey(keyParams, keyFormat, keyData, hidl_cb));
+        if (!rc.isOk()) {
+            return worker_cb(rc, {});
+        }
+
+        if (consider_fallback && !error.isOk()) {
+            auto fallback = keyStore_->getFallbackDevice();
+            if (!fallback) {
+                return worker_cb(error, {});
+            }
+            // No fallback for 3DES
+            for (auto& param : keyParams) {
+                auto algorithm = authorizationValue(TAG_ALGORITHM, param);
+                if (algorithm.isOk() && algorithm.value() == Algorithm::TRIPLE_DES) {
+                    return worker_cb(ErrorCode::UNSUPPORTED_ALGORITHM, {});
+                }
+            }
+
+            // delegate to fallback worker
+            fallback->importKey(std::move(lockedEntry), std::move(keyParams), keyFormat,
+                                std::move(keyData), flags, std::move(worker_cb));
+            // let fallback to the logging
+            logOnFail.release();
+            return;
+        }
+
+        if (!error.isOk()) return worker_cb(error, {});
+
+        // log on success
+        logOnFail.release();
+        uploadKeyCharacteristicsAsProto(keyParams, true /* wasCreationSuccessful */);
+
+        return worker_cb(error, std::move(outCharacteristics));
+    });
+}
+
+void KeymasterWorker::importWrappedKey(LockedKeyBlobEntry wrappingLockedEntry,
+                                       LockedKeyBlobEntry wrapppedLockedEntry,
+                                       hidl_vec<uint8_t> wrappedKeyData,
+                                       hidl_vec<uint8_t> maskingKey,
+                                       hidl_vec<KeyParameter> unwrappingParams, Blob wrappingBlob,
+                                       Blob wrappingCharBlob, uint64_t passwordSid,
+                                       uint64_t biometricSid, importWrappedKey_cb worker_cb) {
+    Worker::addRequest([this, CAPTURE_MOVE(wrappingLockedEntry), CAPTURE_MOVE(wrapppedLockedEntry),
+                        CAPTURE_MOVE(wrappedKeyData), CAPTURE_MOVE(maskingKey),
+                        CAPTURE_MOVE(unwrappingParams), CAPTURE_MOVE(wrappingBlob),
+                        CAPTURE_MOVE(wrappingCharBlob), passwordSid, biometricSid,
+                        CAPTURE_MOVE(worker_cb)]() mutable {
+        auto hidlWrappingKey = blob2hidlVec(wrappingBlob);
+
+        SecurityLevel securityLevel = keymasterDevice_->halVersion().securityLevel;
+
+        KeyCharacteristics outCharacteristics;
+        KeyStoreServiceReturnCode error;
+
+        auto hidlCb = [&](ErrorCode ret, const hidl_vec<uint8_t>& hidlKeyBlob,
+                          const KeyCharacteristics& keyCharacteristics) {
+            error = ret;
+            if (!error.isOk()) {
+                return;
+            }
+            outCharacteristics = keyCharacteristics;
+
+            Blob keyBlob(hidlKeyBlob.data(), hidlKeyBlob.size(), nullptr, 0, ::TYPE_KEYMASTER_10);
+            keyBlob.setSecurityLevel(securityLevel);
+            if (isAuthenticationBound(keyCharacteristics.hardwareEnforced)) {
+                keyBlob.setSuperEncrypted(true);
+            }
+
+            AuthorizationSet sw_enforced = outCharacteristics.softwareEnforced;
+            if (!sw_enforced.Contains(Tag::USER_ID)) {
+                // Most Java processes don't have access to this tag
+                sw_enforced.push_back(keymaster::TAG_USER_ID,
+                                      get_user_id(wrapppedLockedEntry->uid()));
+            }
+            Blob keyCharBlob;
+            keyCharBlob.putKeyCharacteristics(outCharacteristics.hardwareEnforced, sw_enforced);
+            error = keyStore_->put(wrapppedLockedEntry, std::move(keyBlob), std::move(keyCharBlob));
+        };
+
+        KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(keymasterDevice_->importWrappedKey(
+            wrappedKeyData, hidlWrappingKey, maskingKey, unwrappingParams, passwordSid,
+            biometricSid, hidlCb));
+
+        // possible hidl error
+        if (!rc.isOk()) {
+            return worker_cb(rc, {});
+        }
+
+        if (error == ErrorCode::KEY_REQUIRES_UPGRADE) {
+            std::tie(rc, wrappingBlob) = upgradeKeyBlob(wrappingLockedEntry, {});
+            if (!rc.isOk()) {
+                return worker_cb(rc, {});
+            }
+
+            auto upgradedHidlKeyBlob = blob2hidlVec(wrappingBlob);
+
+            rc = KS_HANDLE_HIDL_ERROR(keymasterDevice_->importWrappedKey(
+                wrappedKeyData, upgradedHidlKeyBlob, maskingKey, unwrappingParams, passwordSid,
+                biometricSid, hidlCb));
+            if (!rc.isOk()) {
+                error = rc;
+            }
+        }
+        return worker_cb(error, std::move(outCharacteristics));
+    });
+}
+
+void KeymasterWorker::exportKey(LockedKeyBlobEntry lockedEntry, KeyFormat exportFormat,
+                                hidl_vec<uint8_t> clientId, hidl_vec<uint8_t> appData, Blob keyBlob,
+                                Blob charBlob, exportKey_cb worker_cb) {
+    Worker::addRequest([this, CAPTURE_MOVE(lockedEntry), exportFormat, CAPTURE_MOVE(clientId),
+                        CAPTURE_MOVE(appData), CAPTURE_MOVE(keyBlob), CAPTURE_MOVE(charBlob),
+                        CAPTURE_MOVE(worker_cb)]() mutable {
+        auto key = blob2hidlVec(keyBlob);
+
+        ExportResult result;
+        auto hidlCb = [&](ErrorCode ret,
+                          const ::android::hardware::hidl_vec<uint8_t>& keyMaterial) {
+            result.resultCode = ret;
+            if (!result.resultCode.isOk()) {
+                if (result.resultCode == ErrorCode::INVALID_KEY_BLOB) {
+                    log_key_integrity_violation(lockedEntry->alias().c_str(), lockedEntry->uid());
+                }
+                return;
+            }
+            result.exportData = keyMaterial;
+        };
+        KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(
+            keymasterDevice_->exportKey(exportFormat, key, clientId, appData, hidlCb));
+
+        // Overwrite result->resultCode only on HIDL error. Otherwise we want the result set in the
+        // callback hidlCb.
+        if (!rc.isOk()) {
+            result.resultCode = rc;
+        }
+
+        if (result.resultCode == ErrorCode::KEY_REQUIRES_UPGRADE) {
+            AuthorizationSet upgradeParams;
+            if (clientId.size()) {
+                upgradeParams.push_back(TAG_APPLICATION_ID, clientId);
+            }
+            if (appData.size()) {
+                upgradeParams.push_back(TAG_APPLICATION_DATA, appData);
+            }
+            std::tie(rc, keyBlob) = upgradeKeyBlob(lockedEntry, upgradeParams);
+            if (!rc.isOk()) {
+                return worker_cb(std::move(result));
+            }
+
+            auto upgradedHidlKeyBlob = blob2hidlVec(keyBlob);
+
+            rc = KS_HANDLE_HIDL_ERROR(keymasterDevice_->exportKey(exportFormat, upgradedHidlKeyBlob,
+                                                                  clientId, appData, hidlCb));
+            if (!rc.isOk()) {
+                result.resultCode = rc;
+            }
+        }
+        return worker_cb(std::move(result));
+    });
+}
+void KeymasterWorker::attestKey(hidl_vec<uint8_t> keyToAttest, hidl_vec<KeyParameter> attestParams,
+                                attestKey_cb worker_cb) {
+    addRequest(&Keymaster::attestKey, std::move(worker_cb), std::move(keyToAttest),
+               std::move(attestParams));
+}
+void KeymasterWorker::upgradeKey(hidl_vec<uint8_t> keyBlobToUpgrade,
+                                 hidl_vec<KeyParameter> upgradeParams, upgradeKey_cb _hidl_cb) {
+    addRequest(&Keymaster::upgradeKey, std::move(_hidl_cb), std::move(keyBlobToUpgrade),
+               std::move(upgradeParams));
+}
+
+void KeymasterWorker::deleteKey(hidl_vec<uint8_t> keyBlob, deleteKey_cb _hidl_cb) {
+    addRequest(&Keymaster::deleteKey, std::move(_hidl_cb), std::move(keyBlob));
+}
+void KeymasterWorker::deleteAllKeys(deleteAllKeys_cb _hidl_cb) {
+    addRequest(&Keymaster::deleteAllKeys, std::move(_hidl_cb));
+}
+void KeymasterWorker::destroyAttestationIds(destroyAttestationIds_cb _hidl_cb) {
+    addRequest(&Keymaster::destroyAttestationIds, move(_hidl_cb));
+}
+
+void KeymasterWorker::binderDied(android::wp<IBinder> who) {
+    Worker::addRequest([this, who]() {
+        auto operations = operationMap_.getOperationsForToken(who.unsafe_get());
+        for (const auto& token : operations) {
+            abort(token);
+        }
+    });
+}
+
+}  // namespace keystore
diff --git a/keystore/keymaster_worker.h b/keystore/keymaster_worker.h
new file mode 100644
index 0000000..b39ae83
--- /dev/null
+++ b/keystore/keymaster_worker.h
@@ -0,0 +1,306 @@
+/*
+**
+** Copyright 2018, 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 KEYSTORE_KEYMASTER_WORKER_H_
+#define KEYSTORE_KEYMASTER_WORKER_H_
+
+#include <condition_variable>
+#include <functional>
+#include <keymasterV4_0/Keymaster.h>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <queue>
+#include <thread>
+#include <tuple>
+
+#include <keystore/ExportResult.h>
+#include <keystore/KeyCharacteristics.h>
+#include <keystore/KeymasterBlob.h>
+#include <keystore/OperationResult.h>
+#include <keystore/keystore_return_types.h>
+
+#include "blob.h"
+#include "operation.h"
+
+namespace keystore {
+
+using android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using android::hardware::keymaster::V4_0::ErrorCode;
+using android::hardware::keymaster::V4_0::HardwareAuthToken;
+using android::hardware::keymaster::V4_0::HmacSharingParameters;
+using android::hardware::keymaster::V4_0::KeyCharacteristics;
+using android::hardware::keymaster::V4_0::KeyFormat;
+using android::hardware::keymaster::V4_0::KeyParameter;
+using android::hardware::keymaster::V4_0::KeyPurpose;
+using android::hardware::keymaster::V4_0::VerificationToken;
+using android::hardware::keymaster::V4_0::support::Keymaster;
+// using KeystoreCharacteristics = ::android::security::keymaster::KeyCharacteristics;
+using ::android::security::keymaster::KeymasterBlob;
+
+class KeyStore;
+
+class Worker {
+
+    /*
+     * NonCopyableFunction works similar to std::function in that it wraps callable objects and
+     * erases their type. The rationale for using a custom class instead of
+     * std::function is that std::function requires the wrapped object to be copy contructible.
+     * NonCopyableFunction is itself not copyable and never attempts to copy the wrapped object.
+     * TODO use similar optimization as std::function to remove the extra make_unique allocation.
+     */
+    template <typename Fn> class NonCopyableFunction;
+
+    template <typename Ret, typename... Args> class NonCopyableFunction<Ret(Args...)> {
+
+        class NonCopyableFunctionBase {
+          public:
+            NonCopyableFunctionBase() = default;
+            virtual ~NonCopyableFunctionBase() {}
+            virtual Ret operator()(Args... args) = 0;
+            NonCopyableFunctionBase(const NonCopyableFunctionBase&) = delete;
+            NonCopyableFunctionBase& operator=(const NonCopyableFunctionBase&) = delete;
+        };
+
+        template <typename Fn>
+        class NonCopyableFunctionTypeEraser : public NonCopyableFunctionBase {
+          private:
+            Fn f_;
+
+          public:
+            NonCopyableFunctionTypeEraser() = default;
+            explicit NonCopyableFunctionTypeEraser(Fn f) : f_(std::move(f)) {}
+            Ret operator()(Args... args) override { return f_(std::move(args)...); }
+        };
+
+      private:
+        std::unique_ptr<NonCopyableFunctionBase> f_;
+
+      public:
+        NonCopyableFunction() = default;
+        template <typename F> NonCopyableFunction(F f) {
+            f_ = std::make_unique<NonCopyableFunctionTypeEraser<F>>(std::move(f));
+        }
+        NonCopyableFunction(NonCopyableFunction&& other) = default;
+        NonCopyableFunction& operator=(NonCopyableFunction&& other) = default;
+        NonCopyableFunction(const NonCopyableFunction& other) = delete;
+        NonCopyableFunction& operator=(const NonCopyableFunction& other) = delete;
+
+        Ret operator()(Args... args) {
+            if (f_) return (*f_)(std::move(args)...);
+        }
+    };
+
+    using WorkerTask = NonCopyableFunction<void()>;
+
+    std::queue<WorkerTask> pending_requests_;
+    std::mutex pending_requests_mutex_;
+    std::condition_variable pending_requests_cond_var_;
+    std::thread worker_;
+    bool running_ = false;
+
+  public:
+    Worker();
+    ~Worker();
+    void addRequest(WorkerTask request);
+};
+
+template <typename... Args> struct MakeKeymasterWorkerCB;
+
+template <typename ErrorType, typename... Args>
+struct MakeKeymasterWorkerCB<ErrorType, std::function<void(Args...)>> {
+    using type = std::function<void(ErrorType, std::tuple<std::decay_t<Args>...>&&)>;
+};
+
+template <typename ErrorType> struct MakeKeymasterWorkerCB<ErrorType> {
+    using type = std::function<void(ErrorType)>;
+};
+
+template <typename... Args>
+using MakeKeymasterWorkerCB_t = typename MakeKeymasterWorkerCB<Args...>::type;
+
+class KeymasterWorker : protected Worker {
+  private:
+    sp<Keymaster> keymasterDevice_;
+    OperationMap operationMap_;
+    KeyStore* keyStore_;
+
+    template <typename KMFn, typename ErrorType, typename... Args, size_t... I>
+    void unwrap_tuple(KMFn kmfn, std::function<void(ErrorType)> cb,
+                      const std::tuple<Args...>& tuple, std::index_sequence<I...>) {
+        cb(((*keymasterDevice_).*kmfn)(std::get<I>(tuple)...));
+    }
+
+    template <typename KMFn, typename ErrorType, typename... ReturnTypes, typename... Args,
+              size_t... I>
+    void unwrap_tuple(KMFn kmfn, std::function<void(ErrorType, std::tuple<ReturnTypes...>&&)> cb,
+                      const std::tuple<Args...>& tuple, std::index_sequence<I...>) {
+        std::tuple<ReturnTypes...> returnValue;
+        auto result = ((*keymasterDevice_).*kmfn)(
+            std::get<I>(tuple)...,
+            [&returnValue](const ReturnTypes&... args) { returnValue = std::make_tuple(args...); });
+        cb(std::move(result), std::move(returnValue));
+    }
+
+    template <typename KMFn, typename ErrorType, typename... Args>
+    void addRequest(KMFn kmfn, std::function<void(ErrorType)> cb, Args&&... args) {
+        Worker::addRequest([this, kmfn, cb = std::move(cb),
+                            tuple = std::make_tuple(std::forward<Args>(args)...)]() {
+            unwrap_tuple(kmfn, std::move(cb), tuple, std::index_sequence_for<Args...>{});
+        });
+    }
+
+    template <typename KMFn, typename ErrorType, typename... ReturnTypes, typename... Args>
+    void addRequest(KMFn kmfn, std::function<void(ErrorType, std::tuple<ReturnTypes...>&&)> cb,
+                    Args&&... args) {
+        Worker::addRequest([this, kmfn, cb = std::move(cb),
+                            tuple = std::make_tuple(std::forward<Args>(args)...)]() {
+            unwrap_tuple(kmfn, std::move(cb), tuple, std::index_sequence_for<Args...>{});
+        });
+    }
+    std::tuple<KeyStoreServiceReturnCode, Blob>
+    upgradeKeyBlob(const LockedKeyBlobEntry& lockedEntry, const AuthorizationSet& params);
+    std::tuple<KeyStoreServiceReturnCode, KeyCharacteristics, Blob, Blob>
+    createKeyCharacteristicsCache(const LockedKeyBlobEntry& lockedEntry,
+                                  const hidl_vec<uint8_t>& clientId,
+                                  const hidl_vec<uint8_t>& appData, Blob keyBlob, Blob charBlob);
+
+    /**
+     * Get the auth token for this operation from the auth token table.
+     *
+     * Returns NO_ERROR if the auth token was found or none was required.  If not needed, the
+     *             token will be empty (which keymaster interprets as no auth token).
+     *         OP_AUTH_NEEDED if it is a per op authorization, no authorization token exists for
+     *             that operation and  failOnTokenMissing is false.
+     *         KM_ERROR_KEY_USER_NOT_AUTHENTICATED if there is no valid auth token for the operation
+     */
+    std::pair<KeyStoreServiceReturnCode, HardwareAuthToken>
+    getAuthToken(const KeyCharacteristics& characteristics, uint64_t handle, KeyPurpose purpose,
+                 bool failOnTokenMissing = true);
+
+    KeyStoreServiceReturnCode abort(const sp<IBinder>& token);
+
+    bool pruneOperation();
+
+    KeyStoreServiceReturnCode getOperationAuthTokenIfNeeded(std::shared_ptr<Operation> op);
+
+    void appendConfirmationTokenIfNeeded(const KeyCharacteristics& keyCharacteristics,
+                                         hidl_vec<KeyParameter>* params);
+
+  public:
+    KeymasterWorker(sp<Keymaster> keymasterDevice, KeyStore* keyStore);
+
+    using worker_begin_cb = std::function<void(::android::security::keymaster::OperationResult)>;
+    void begin(LockedKeyBlobEntry, sp<IBinder> appToken, Blob keyBlob, Blob charBlob,
+               bool pruneable, KeyPurpose purpose, AuthorizationSet opParams,
+               hidl_vec<uint8_t> entropy, worker_begin_cb worker_cb);
+
+    using update_cb = std::function<void(::android::security::keymaster::OperationResult)>;
+    void update(sp<IBinder> token, AuthorizationSet params, hidl_vec<uint8_t> data,
+                update_cb _hidl_cb);
+
+    using finish_cb = std::function<void(::android::security::keymaster::OperationResult)>;
+    void finish(sp<IBinder> token, AuthorizationSet params, hidl_vec<uint8_t> input,
+                hidl_vec<uint8_t> signature, hidl_vec<uint8_t> entorpy, finish_cb worker_cb);
+
+    using abort_cb = std::function<void(KeyStoreServiceReturnCode)>;
+    void abort(sp<IBinder> token, abort_cb _hidl_cb);
+
+    using getHardwareInfo_cb = MakeKeymasterWorkerCB_t<Return<void>, Keymaster::getHardwareInfo_cb>;
+    void getHardwareInfo(getHardwareInfo_cb _hidl_cb);
+
+    using getHmacSharingParameters_cb =
+        MakeKeymasterWorkerCB_t<Return<void>, Keymaster::getHmacSharingParameters_cb>;
+    void getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb);
+
+    using computeSharedHmac_cb =
+        MakeKeymasterWorkerCB_t<Return<void>, Keymaster::computeSharedHmac_cb>;
+    void computeSharedHmac(hidl_vec<HmacSharingParameters> params, computeSharedHmac_cb _hidl_cb);
+
+    using verifyAuthorization_cb =
+        std::function<void(KeyStoreServiceReturnCode ec, HardwareAuthToken, VerificationToken)>;
+    void verifyAuthorization(uint64_t challenge, hidl_vec<KeyParameter> params,
+                             HardwareAuthToken token, verifyAuthorization_cb _hidl_cb);
+
+    using addRngEntropy_cb = MakeKeymasterWorkerCB_t<Return<ErrorCode>>;
+    void addRngEntropy(hidl_vec<uint8_t> data, addRngEntropy_cb _hidl_cb);
+
+    using generateKey_cb = std::function<void(
+        KeyStoreServiceReturnCode, ::android::hardware::keymaster::V4_0::KeyCharacteristics)>;
+    void generateKey(LockedKeyBlobEntry, hidl_vec<KeyParameter> keyParams,
+                     hidl_vec<uint8_t> entropy, int flags, generateKey_cb _hidl_cb);
+
+    using generateKey2_cb = MakeKeymasterWorkerCB_t<Return<void>, Keymaster::generateKey_cb>;
+    void generateKey(hidl_vec<KeyParameter> keyParams, generateKey2_cb _hidl_cb);
+
+    using getKeyCharacteristics_cb = std::function<void(
+        KeyStoreServiceReturnCode, ::android::hardware::keymaster::V4_0::KeyCharacteristics)>;
+    void getKeyCharacteristics(LockedKeyBlobEntry lockedEntry, hidl_vec<uint8_t> clientId,
+                               hidl_vec<uint8_t> appData, Blob keyBlob, Blob charBlob,
+                               getKeyCharacteristics_cb _hidl_cb);
+
+    using importKey_cb = std::function<void(
+        KeyStoreServiceReturnCode, ::android::hardware::keymaster::V4_0::KeyCharacteristics)>;
+    void importKey(LockedKeyBlobEntry lockedEntry, hidl_vec<KeyParameter> params,
+                   KeyFormat keyFormat, hidl_vec<uint8_t> keyData, int flags,
+                   importKey_cb _hidl_cb);
+
+    using importWrappedKey_cb = std::function<void(
+        KeyStoreServiceReturnCode, ::android::hardware::keymaster::V4_0::KeyCharacteristics)>;
+    void importWrappedKey(LockedKeyBlobEntry wrappingLockedEntry,
+                          LockedKeyBlobEntry wrapppedLockedEntry, hidl_vec<uint8_t> wrappedKeyData,
+                          hidl_vec<uint8_t> maskingKey, hidl_vec<KeyParameter> unwrappingParams,
+                          Blob wrappingBlob, Blob wrappingCharBlob, uint64_t passwordSid,
+                          uint64_t biometricSid, importWrappedKey_cb worker_cb);
+
+    using exportKey_cb = std::function<void(::android::security::keymaster::ExportResult)>;
+    void exportKey(LockedKeyBlobEntry lockedEntry, KeyFormat exportFormat,
+                   hidl_vec<uint8_t> clientId, hidl_vec<uint8_t> appData, Blob keyBlob,
+                   Blob charBlob, exportKey_cb _hidl_cb);
+
+    using attestKey_cb = MakeKeymasterWorkerCB_t<Return<void>, Keymaster::attestKey_cb>;
+    void attestKey(hidl_vec<uint8_t> keyToAttest, hidl_vec<KeyParameter> attestParams,
+                   attestKey_cb _hidl_cb);
+
+    using upgradeKey_cb = MakeKeymasterWorkerCB_t<Return<void>, Keymaster::upgradeKey_cb>;
+    void upgradeKey(hidl_vec<uint8_t> keyBlobToUpgrade, hidl_vec<KeyParameter> upgradeParams,
+                    upgradeKey_cb _hidl_cb);
+
+    using deleteKey_cb = MakeKeymasterWorkerCB_t<Return<ErrorCode>>;
+    void deleteKey(hidl_vec<uint8_t> keyBlob, deleteKey_cb _hidl_cb);
+
+    using deleteAllKeys_cb = MakeKeymasterWorkerCB_t<Return<ErrorCode>>;
+    void deleteAllKeys(deleteAllKeys_cb _hidl_cb);
+
+    using destroyAttestationIds_cb = MakeKeymasterWorkerCB_t<Return<ErrorCode>>;
+    void destroyAttestationIds(destroyAttestationIds_cb _hidl_cb);
+
+    using begin_cb = MakeKeymasterWorkerCB_t<Return<void>, Keymaster::begin_cb>;
+    void begin(KeyPurpose purpose, hidl_vec<uint8_t> key, hidl_vec<KeyParameter> inParams,
+               HardwareAuthToken authToken, begin_cb _hidl_cb);
+
+    void binderDied(android::wp<IBinder> who);
+
+    const Keymaster::VersionResult& halVersion() { return keymasterDevice_->halVersion(); }
+};
+
+}  // namespace keystore
+
+#endif  // KEYSTORE_KEYMASTER_WORKER_H_
diff --git a/keystore/keystore_main.cpp b/keystore/keystore_main.cpp
index 82d4e69..c05d142 100644
--- a/keystore/keystore_main.cpp
+++ b/keystore/keystore_main.cpp
@@ -155,10 +155,11 @@
     SecurityLevel minimalAllowedSecurityLevelForNewKeys =
         halVersion.majorVersion >= 2 ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE;
 
-    keystore::KeyStore keyStore(&entropy, kmDevices, minimalAllowedSecurityLevelForNewKeys);
-    keyStore.initialize();
+    android::sp<keystore::KeyStore> keyStore(
+        new keystore::KeyStore(&entropy, kmDevices, minimalAllowedSecurityLevelForNewKeys));
+    keyStore->initialize();
     android::sp<android::IServiceManager> sm = android::defaultServiceManager();
-    android::sp<keystore::KeyStoreService> service = new keystore::KeyStoreService(&keyStore);
+    android::sp<keystore::KeyStoreService> service = new keystore::KeyStoreService(keyStore);
     android::status_t ret = sm->addService(android::String16("android.security.keystore"), service);
     CHECK(ret == android::OK) << "Couldn't register binder service!";
 
diff --git a/keystore/operation.cpp b/keystore/operation.cpp
index 4069060..07f9d6c 100644
--- a/keystore/operation.cpp
+++ b/keystore/operation.cpp
@@ -18,6 +18,8 @@
 #include "operation.h"
 
 #include <algorithm>
+#include <android-base/logging.h>
+#include <mutex>
 
 namespace keystore {
 
@@ -29,20 +31,22 @@
                                        KeyCharacteristics&& characteristics,
                                        const hidl_vec<KeyParameter>& params, bool pruneable) {
     sp<IBinder> token = new ::android::BBinder();
-    mMap.emplace(token, Operation(handle, keyid, purpose, dev, std::move(characteristics), appToken,
-                                  params));
+    mMap.emplace(token, std::make_shared<Operation>(handle, keyid, purpose, dev,
+                                                    std::move(characteristics), appToken, params));
     if (pruneable) mLru.push_back(token);
     if (mAppTokenMap.find(appToken) == mAppTokenMap.end()) appToken->linkToDeath(mDeathRecipient);
     mAppTokenMap[appToken].push_back(token);
     return token;
 }
 
-NullOr<const Operation&> OperationMap::getOperation(const sp<IBinder>& token) {
+std::shared_ptr<Operation> OperationMap::getOperation(const sp<IBinder>& token) {
     auto entry = mMap.find(token);
     if (entry == mMap.end()) return {};
 
+    auto op = entry->second;
+
     updateLru(token);
-    return entry->second;
+    return op;
 }
 
 void OperationMap::updateLru(const sp<IBinder>& token) {
@@ -53,17 +57,18 @@
     }
 }
 
-NullOr<Operation> OperationMap::removeOperation(const sp<IBinder>& token, bool wasSuccessful) {
+std::shared_ptr<Operation> OperationMap::removeOperation(const sp<IBinder>& token,
+                                                         bool wasSuccessful) {
     auto entry = mMap.find(token);
     if (entry == mMap.end()) return {};
 
-    Operation op = std::move(entry->second);
-    uploadOpAsProto(op, wasSuccessful);
+    auto op = entry->second;
+    uploadOpAsProto(*op, wasSuccessful);
     mMap.erase(entry);
 
     auto lruEntry = std::find(mLru.begin(), mLru.end(), token);
     if (lruEntry != mLru.end()) mLru.erase(lruEntry);
-    removeOperationTracking(token, op.appToken);
+    removeOperationTracking(token, op->appToken);
     return op;
 }
 
@@ -82,32 +87,10 @@
     }
 }
 
-bool OperationMap::hasPruneableOperation() const {
-    return !mLru.empty();
-}
-
-size_t OperationMap::getPruneableOperationCount() const {
-    return mLru.size();
-}
-
 sp<IBinder> OperationMap::getOldestPruneableOperation() {
-    if (!hasPruneableOperation()) return sp<IBinder>(nullptr);
-    return mLru.front();
-}
+    if (mLru.size() == 0) return {};
 
-void OperationMap::setOperationAuthToken(const sp<IBinder>& token, HardwareAuthToken authToken) {
-    auto entry = mMap.find(token);
-    if (entry == mMap.end()) return;
-
-    entry->second.authToken = std::move(authToken);
-}
-
-void OperationMap::setOperationVerificationToken(const sp<IBinder>& token,
-                                                 VerificationToken verificationToken) {
-    auto entry = mMap.find(token);
-    if (entry == mMap.end()) return;
-
-    entry->second.verificationToken = std::move(verificationToken);
+    return {mLru.front()};
 }
 
 std::vector<sp<IBinder>> OperationMap::getOperationsForToken(const sp<IBinder>& appToken) {
diff --git a/keystore/operation.h b/keystore/operation.h
index 4888bfa..efe791f 100644
--- a/keystore/operation.h
+++ b/keystore/operation.h
@@ -17,7 +17,11 @@
 #ifndef KEYSTORE_OPERATION_H_
 #define KEYSTORE_OPERATION_H_
 
+#include <list>
 #include <map>
+#include <memory>
+#include <mutex>
+#include <optional>
 #include <vector>
 
 #include <binder/Binder.h>
@@ -26,6 +30,7 @@
 #include <utils/StrongPointer.h>
 
 #include <keystore/keymaster_types.h>
+#include <keystore/keystore_concurrency.h>
 #include <keystore/keystore_hidl_support.h>
 
 #include "operation_proto_handler.h"
@@ -51,21 +56,18 @@
                              const sp<Keymaster>& dev, const sp<IBinder>& appToken,
                              KeyCharacteristics&& characteristics,
                              const hidl_vec<KeyParameter>& params, bool pruneable);
-    NullOr<const Operation&> getOperation(const sp<IBinder>& token);
-    NullOr<Operation> removeOperation(const sp<IBinder>& token, bool wasSuccessful);
-    bool hasPruneableOperation() const;
+    std::shared_ptr<Operation> getOperation(const sp<IBinder>& token);
+    std::shared_ptr<Operation> removeOperation(const sp<IBinder>& token, bool wasSuccessful);
     size_t getOperationCount() const { return mMap.size(); }
-    size_t getPruneableOperationCount() const;
-    void setOperationAuthToken(const sp<IBinder>& token, HardwareAuthToken authToken);
-    void setOperationVerificationToken(const sp<IBinder>& token, VerificationToken authToken);
     sp<IBinder> getOldestPruneableOperation();
     std::vector<sp<IBinder>> getOperationsForToken(const sp<IBinder>& appToken);
 
   private:
     void updateLru(const sp<IBinder>& token);
     void removeOperationTracking(const sp<IBinder>& token, const sp<IBinder>& appToken);
-    std::map<sp<IBinder>, Operation> mMap;
-    std::vector<sp<IBinder>> mLru;
+
+    std::map<sp<IBinder>, std::shared_ptr<Operation>> mMap;
+    std::list<sp<IBinder>> mLru;
     std::map<sp<IBinder>, std::vector<sp<IBinder>>> mAppTokenMap;
     IBinder::DeathRecipient* mDeathRecipient;
 };
diff --git a/keystore/operation_struct.h b/keystore/operation_struct.h
index 00f1fe2..84265b6 100644
--- a/keystore/operation_struct.h
+++ b/keystore/operation_struct.h
@@ -24,6 +24,9 @@
 
 #include <keystore/keymaster_types.h>
 #include <keystore/keystore_hidl_support.h>
+#include <keystore/keystore_return_types.h>
+
+#include <future>
 
 namespace keystore {
 
@@ -37,7 +40,8 @@
               KeyCharacteristics&& characteristics_, sp<IBinder> appToken_,
               const hidl_vec<KeyParameter> params_)
         : handle(handle_), keyid(keyid_), purpose(purpose_), device(device_),
-          characteristics(characteristics_), appToken(appToken_), params(params_) {}
+          characteristics(characteristics_), appToken(appToken_), authToken(), verificationToken(),
+          params(params_) {}
     Operation(Operation&&) = default;
     Operation(const Operation&) = delete;
 
@@ -49,6 +53,8 @@
     sp<Keymaster> device;
     KeyCharacteristics characteristics;
     sp<IBinder> appToken;
+    std::promise<KeyStoreServiceReturnCode> authTokenPromise;
+    std::future<KeyStoreServiceReturnCode> authTokenFuture;
     HardwareAuthToken authToken;
     VerificationToken verificationToken;
     const hidl_vec<KeyParameter> params;
diff --git a/keystore/tests/auth_token_table_test.cpp b/keystore/tests/auth_token_table_test.cpp
index 29aa71e..f6ce10e 100644
--- a/keystore/tests/auth_token_table_test.cpp
+++ b/keystore/tests/auth_token_table_test.cpp
@@ -96,30 +96,36 @@
     table.AddAuthenticationToken(make_token(3, 4));
     EXPECT_EQ(2U, table.size());
 
-    const HardwareAuthToken* found;
+    AuthTokenTable::Error rc;
+    HardwareAuthToken found;
 
-    ASSERT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(1U, found->userId);
-    EXPECT_EQ(2U, found->authenticatorId);
+    ASSERT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(1U, found.userId);
+    EXPECT_EQ(2U, found.authenticatorId);
 
-    ASSERT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(1U, found->userId);
-    EXPECT_EQ(2U, found->authenticatorId);
+    ASSERT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(1U, found.userId);
+    EXPECT_EQ(2U, found.authenticatorId);
 
-    ASSERT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(3U, found->userId);
-    EXPECT_EQ(4U, found->authenticatorId);
+    ASSERT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(3U, found.userId);
+    EXPECT_EQ(4U, found.authenticatorId);
 
-    ASSERT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(3U, found->userId);
-    EXPECT_EQ(4U, found->authenticatorId);
+    ASSERT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(3U, found.userId);
+    EXPECT_EQ(4U, found.authenticatorId);
 
-    ASSERT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
-              table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0, &found));
+    ASSERT_EQ(
+        AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0), rc));
 }
 
 TEST(AuthTokenTableTest, FlushTable) {
@@ -129,16 +135,20 @@
     table.AddAuthenticationToken(make_token(2));
     table.AddAuthenticationToken(make_token(3));
 
-    const HardwareAuthToken* found;
+    AuthTokenTable::Error rc;
+    HardwareAuthToken found;
 
     // All three should be in the table.
     EXPECT_EQ(3U, table.size());
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0, &found));
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
 
     table.Clear();
     EXPECT_EQ(0U, table.size());
@@ -151,61 +161,78 @@
     table.AddAuthenticationToken(make_token(2));
     table.AddAuthenticationToken(make_token(3));
 
-    const HardwareAuthToken* found;
+    AuthTokenTable::Error rc;
+    HardwareAuthToken found;
 
     // All three should be in the table.
     EXPECT_EQ(3U, table.size());
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0, &found));
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
 
     table.AddAuthenticationToken(make_token(4));
 
     // Oldest should be gone.
     EXPECT_EQ(3U, table.size());
-    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
-              table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0, &found));
+    EXPECT_EQ(
+        AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
 
     // Others should be there, including the new one (4).  Search for it first, then the others, so
     // 4 becomes the least recently used.
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0, &found));
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
 
     table.AddAuthenticationToken(make_token(5));
 
     // 5 should have replaced 4.
     EXPECT_EQ(3U, table.size());
-    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
-              table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0, &found));
+    EXPECT_EQ(
+        AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
 
     table.AddAuthenticationToken(make_token(6));
     table.AddAuthenticationToken(make_token(7));
 
     // 2 and 5 should be gone
     EXPECT_EQ(3U, table.size());
-    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
-              table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
-              table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(6), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(7), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0, &found));
+    EXPECT_EQ(
+        AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(6), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(7), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
 
     table.AddAuthenticationToken(make_token(8));
     table.AddAuthenticationToken(make_token(9));
@@ -213,77 +240,100 @@
 
     // Only the three most recent should be there.
     EXPECT_EQ(3U, table.size());
-    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
-              table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
-              table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
-              table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
-              table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
-              table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
-              table.FindAuthorization(make_set(6), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
-              table.FindAuthorization(make_set(7), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(8), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(9), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(10), KeyPurpose::SIGN, 0, &found));
+    EXPECT_EQ(
+        AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(6), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(7), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(8), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(9), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(10), KeyPurpose::SIGN, 0), rc));
 }
 
 TEST(AuthTokenTableTest, AuthenticationNotRequired) {
     AuthTokenTable table;
-    const HardwareAuthToken* found;
+    AuthTokenTable::Error rc;
+    HardwareAuthToken found;
 
     EXPECT_EQ(AuthTokenTable::AUTH_NOT_REQUIRED,
-              table.FindAuthorization(AuthorizationSetBuilder().Authorization(TAG_NO_AUTH_REQUIRED),
-                                      KeyPurpose::SIGN, 0 /* no challenge */, &found));
+              (std::tie(rc, found) = table.FindAuthorization(
+                   AuthorizationSetBuilder().Authorization(TAG_NO_AUTH_REQUIRED), KeyPurpose::SIGN,
+                   0 /* no challenge */),
+               rc));
 }
 
 TEST(AuthTokenTableTest, OperationHandleNotFound) {
     AuthTokenTable table;
-    const HardwareAuthToken* found;
+    AuthTokenTable::Error rc;
+    HardwareAuthToken found;
 
     table.AddAuthenticationToken(make_token(1, 0, 1, 5));
     EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
-              table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
-                                      2 /* non-matching challenge */, &found));
+              (std::tie(rc, found) =
+                   table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
+                                           2 /* non-matching challenge */),
+               rc));
     EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
-                                      1 /* matching challenge */, &found));
+              (std::tie(rc, found) = table.FindAuthorization(
+                   make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 1 /* matching challenge */),
+               rc));
     table.MarkCompleted(1);
     EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
-              table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
-                                      1 /* used challenge */, &found));
+              (std::tie(rc, found) = table.FindAuthorization(
+                   make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 1 /* used challenge */),
+               rc));
 }
 
 TEST(AuthTokenTableTest, OperationHandleRequired) {
     AuthTokenTable table;
-    const HardwareAuthToken* found;
+    AuthTokenTable::Error rc;
+    HardwareAuthToken found;
 
     table.AddAuthenticationToken(make_token(1));
     EXPECT_EQ(AuthTokenTable::OP_HANDLE_REQUIRED,
-              table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
-                                      0 /* no op handle */, &found));
+              (std::tie(rc, found) = table.FindAuthorization(
+                   make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 0 /* no op handle */),
+               rc));
 }
 
 TEST(AuthTokenTableTest, AuthSidChanged) {
     AuthTokenTable table;
-    const HardwareAuthToken* found;
+    AuthTokenTable::Error rc;
+    HardwareAuthToken found;
 
     table.AddAuthenticationToken(make_token(1, 3, /* op handle */ 1));
     EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_WRONG_SID,
-              table.FindAuthorization(make_set(2, 0 /* no timeout */), KeyPurpose::SIGN,
-                                      1 /* op handle */, &found));
+              (std::tie(rc, found) = table.FindAuthorization(make_set(2, 0 /* no timeout */),
+                                                             KeyPurpose::SIGN, 1 /* op handle */),
+               rc));
 }
 
 TEST(AuthTokenTableTest, TokenExpired) {
     AuthTokenTable table(5, monotonic_clock);
-    const HardwareAuthToken* found;
+    AuthTokenTable::Error rc;
+    HardwareAuthToken found;
 
     auto key_info = make_set(1, 5 /* five second timeout */);
 
@@ -294,18 +344,25 @@
     // expired.  An additional check of the secure timestamp (in the token) will be made by
     // keymaster when the found token is passed to it.
     table.AddAuthenticationToken(make_token(1, 0));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */, &found));
+    EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+                                       key_info, KeyPurpose::SIGN, 0 /* no op handle */),
+                                   rc));
+    EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+                                       key_info, KeyPurpose::SIGN, 0 /* no op handle */),
+                                   rc));
+    EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+                                       key_info, KeyPurpose::SIGN, 0 /* no op handle */),
+                                   rc));
+    EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+                                       key_info, KeyPurpose::SIGN, 0 /* no op handle */),
+                                   rc));
+    EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+                                       key_info, KeyPurpose::SIGN, 0 /* no op handle */),
+                                   rc));
     EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_EXPIRED,
-              table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */, &found));
+              (std::tie(rc, found) =
+                   table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */),
+               rc));
 }
 
 TEST(AuthTokenTableTest, MarkNonexistentEntryCompleted) {
@@ -316,16 +373,18 @@
 
 TEST(AuthTokenTableTest, SupersededEntries) {
     AuthTokenTable table;
-    const HardwareAuthToken* found;
+    AuthTokenTable::Error rc;
+    HardwareAuthToken found;
 
     // Add two identical tokens, without challenges.  The second should supersede the first, based
     // on timestamp (fourth arg to make_token).
     table.AddAuthenticationToken(make_token(1, 0, 0, 0));
     table.AddAuthenticationToken(make_token(1, 0, 0, 1));
     EXPECT_EQ(1U, table.size());
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(1U, found->timestamp);
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(1U, found.timestamp);
 
     // Add a third token, this with a different RSID.  It should not be superseded.
     table.AddAuthenticationToken(make_token(2, 0, 0, 2));
@@ -335,12 +394,14 @@
     table.AddAuthenticationToken(make_token(1, 0, 0, 3));
     table.AddAuthenticationToken(make_token(2, 0, 0, 4));
     EXPECT_EQ(2U, table.size());
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(3U, found->timestamp);
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0, &found));
-    EXPECT_EQ(4U, found->timestamp);
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(3U, found.timestamp);
+    EXPECT_EQ(
+        AuthTokenTable::OK,
+        (std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
+    EXPECT_EQ(4U, found.timestamp);
 
     // Add another, this one with a challenge value.  It should supersede the old one since it is
     // newer, and matches other than the challenge.
@@ -355,45 +416,52 @@
     // Should be able to find each of them, by specifying their challenge, with a key that is not
     // timed (timed keys don't care about challenges).
     EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(1, 0 /* no timeout*/), KeyPurpose::SIGN,
-                                      1 /* challenge */, &found));
-    EXPECT_EQ(5U, found->timestamp);
+              (std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout*/),
+                                                             KeyPurpose::SIGN, 1 /* challenge */),
+               rc));
+    EXPECT_EQ(5U, found.timestamp);
     EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
-                                      2 /* challenge */, &found));
-    EXPECT_EQ(6U, found->timestamp);
+              (std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
+                                                             KeyPurpose::SIGN, 2 /* challenge */),
+               rc));
+    EXPECT_EQ(6U, found.timestamp);
 
     // Add another, without a challenge, and the same timestamp as the last one.  This new one
     // actually could be considered already-superseded, but the table doesn't handle that case,
     // since it seems unlikely to occur in practice.
     table.AddAuthenticationToken(make_token(1, 0, 0, 6));
     EXPECT_EQ(4U, table.size());
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0 /* challenge */, &found));
-    EXPECT_EQ(6U, found->timestamp);
+    EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+                                       make_set(1), KeyPurpose::SIGN, 0 /* challenge */),
+                                   rc));
+    EXPECT_EQ(6U, found.timestamp);
 
     // Add another without a challenge but an increased timestamp. This should supersede the
     // previous challenge-free entry.
     table.AddAuthenticationToken(make_token(1, 0, 0, 7));
     EXPECT_EQ(4U, table.size());
     EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
-                                      2 /* challenge */, &found));
-    EXPECT_EQ(6U, found->timestamp);
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0 /* challenge */, &found));
-    EXPECT_EQ(7U, found->timestamp);
+              (std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
+                                                             KeyPurpose::SIGN, 2 /* challenge */),
+               rc));
+    EXPECT_EQ(6U, found.timestamp);
+    EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+                                       make_set(1), KeyPurpose::SIGN, 0 /* challenge */),
+                                   rc));
+    EXPECT_EQ(7U, found.timestamp);
 
     // Mark the entry with challenge 2 as complete.  Since there's a newer challenge-free entry, the
     // challenge entry will be superseded.
     table.MarkCompleted(2);
     EXPECT_EQ(3U, table.size());
     EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
-              table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
-                                      2 /* challenge */, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0 /* challenge */, &found));
-    EXPECT_EQ(7U, found->timestamp);
+              (std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
+                                                             KeyPurpose::SIGN, 2 /* challenge */),
+               rc));
+    EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+                                       make_set(1), KeyPurpose::SIGN, 0 /* challenge */),
+                                   rc));
+    EXPECT_EQ(7U, found.timestamp);
 
     // Add another SID 1 entry with a challenge.  It supersedes the previous SID 1 entry with
     // no challenge (timestamp 7), but not the one with challenge 1 (timestamp 5).
@@ -401,19 +469,22 @@
     EXPECT_EQ(3U, table.size());
 
     EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
-                                      1 /* challenge */, &found));
-    EXPECT_EQ(5U, found->timestamp);
+              (std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
+                                                             KeyPurpose::SIGN, 1 /* challenge */),
+               rc));
+    EXPECT_EQ(5U, found.timestamp);
 
     EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
-                                      3 /* challenge */, &found));
-    EXPECT_EQ(8U, found->timestamp);
+              (std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
+                                                             KeyPurpose::SIGN, 3 /* challenge */),
+               rc));
+    EXPECT_EQ(8U, found.timestamp);
 
     // SID 2 entry is still there.
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0 /* challenge */, &found));
-    EXPECT_EQ(4U, found->timestamp);
+    EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+                                       make_set(2), KeyPurpose::SIGN, 0 /* challenge */),
+                                   rc));
+    EXPECT_EQ(4U, found.timestamp);
 
     // Mark the entry with challenge 3 as complete.  Since the older challenge 1 entry is
     // incomplete, nothing is superseded.
@@ -421,24 +492,28 @@
     EXPECT_EQ(3U, table.size());
 
     EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
-                                      1 /* challenge */, &found));
-    EXPECT_EQ(5U, found->timestamp);
+              (std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
+                                                             KeyPurpose::SIGN, 1 /* challenge */),
+               rc));
+    EXPECT_EQ(5U, found.timestamp);
 
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0 /* challenge */, &found));
-    EXPECT_EQ(8U, found->timestamp);
+    EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+                                       make_set(1), KeyPurpose::SIGN, 0 /* challenge */),
+                                   rc));
+    EXPECT_EQ(8U, found.timestamp);
 
     // Mark the entry with challenge 1 as complete.  Since there's a newer one (with challenge 3,
     // completed), the challenge 1 entry is superseded and removed.
     table.MarkCompleted(1);
     EXPECT_EQ(2U, table.size());
     EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
-              table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
-                                      1 /* challenge */, &found));
-    EXPECT_EQ(AuthTokenTable::OK,
-              table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0 /* challenge */, &found));
-    EXPECT_EQ(8U, found->timestamp);
+              (std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
+                                                             KeyPurpose::SIGN, 1 /* challenge */),
+               rc));
+    EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+                                       make_set(1), KeyPurpose::SIGN, 0 /* challenge */),
+                                   rc));
+    EXPECT_EQ(8U, found.timestamp);
 }
 
 }  // namespace test
diff --git a/keystore/user_state.cpp b/keystore/user_state.cpp
index af3336b..c9a2d72 100644
--- a/keystore/user_state.cpp
+++ b/keystore/user_state.cpp
@@ -31,25 +31,32 @@
 #include "blob.h"
 #include "keystore_utils.h"
 
+namespace keystore {
 
-UserState::UserState(uid_t userId) :
-        mUserId(userId), mState(STATE_UNINITIALIZED), mRetry(MAX_RETRY) {
-    asprintf(&mUserDir, "user_%u", mUserId);
-    asprintf(&mMasterKeyFile, "%s/.masterkey", mUserDir);
+UserState::UserState(uid_t userId)
+    : mMasterKeyEntry(".masterkey", "user_" + std::to_string(userId), userId, /* masterkey */ true),
+      mUserId(userId), mState(STATE_UNINITIALIZED), mRetry(MAX_RETRY) {}
+
+bool UserState::operator<(const UserState& rhs) const {
+    return getUserId() < rhs.getUserId();
 }
 
-UserState::~UserState() {
-    free(mUserDir);
-    free(mMasterKeyFile);
+bool UserState::operator<(uid_t userId) const {
+    return getUserId() < userId;
+}
+
+bool operator<(uid_t userId, const UserState& rhs) {
+    return userId < rhs.getUserId();
 }
 
 bool UserState::initialize() {
-    if ((mkdir(mUserDir, S_IRUSR | S_IWUSR | S_IXUSR) < 0) && (errno != EEXIST)) {
-        ALOGE("Could not create directory '%s'", mUserDir);
+    if ((mkdir(mMasterKeyEntry.user_dir().c_str(), S_IRUSR | S_IWUSR | S_IXUSR) < 0) &&
+        (errno != EEXIST)) {
+        ALOGE("Could not create directory '%s'", mMasterKeyEntry.user_dir().c_str());
         return false;
     }
 
-    if (access(mMasterKeyFile, R_OK) == 0) {
+    if (mMasterKeyEntry.hasKeyBlob()) {
         setState(STATE_LOCKED);
     } else {
         setState(STATE_UNINITIALIZED);
@@ -73,7 +80,7 @@
 bool UserState::deleteMasterKey() {
     setState(STATE_UNINITIALIZED);
     zeroizeMasterKeysInMemory();
-    return unlink(mMasterKeyFile) == 0 || errno == ENOENT;
+    return unlink(mMasterKeyEntry.getKeyBlobPath().c_str()) == 0 || errno == ENOENT;
 }
 
 ResponseCode UserState::initialize(const android::String8& pw, Entropy* entropy) {
@@ -88,23 +95,23 @@
     return ResponseCode::NO_ERROR;
 }
 
-ResponseCode UserState::copyMasterKey(UserState* src) {
+ResponseCode UserState::copyMasterKey(LockedUserState<UserState>* src) {
     if (mState != STATE_UNINITIALIZED) {
         return ResponseCode::SYSTEM_ERROR;
     }
-    if (src->getState() != STATE_NO_ERROR) {
+    if ((*src)->getState() != STATE_NO_ERROR) {
         return ResponseCode::SYSTEM_ERROR;
     }
-    memcpy(mMasterKey, src->mMasterKey, MASTER_KEY_SIZE_BYTES);
+    memcpy(mMasterKey, (*src)->mMasterKey, MASTER_KEY_SIZE_BYTES);
     setupMasterKeys();
     return copyMasterKeyFile(src);
 }
 
-ResponseCode UserState::copyMasterKeyFile(UserState* src) {
+ResponseCode UserState::copyMasterKeyFile(LockedUserState<UserState>* src) {
     /* Copy the master key file to the new user.  Unfortunately we don't have the src user's
      * password so we cannot generate a new file with a new salt.
      */
-    int in = TEMP_FAILURE_RETRY(open(src->getMasterKeyFileName(), O_RDONLY));
+    int in = TEMP_FAILURE_RETRY(open((*src)->getMasterKeyFileName().c_str(), O_RDONLY));
     if (in < 0) {
         return ResponseCode::SYSTEM_ERROR;
     }
@@ -113,8 +120,8 @@
     if (close(in) != 0) {
         return ResponseCode::SYSTEM_ERROR;
     }
-    int out =
-        TEMP_FAILURE_RETRY(open(mMasterKeyFile, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
+    int out = TEMP_FAILURE_RETRY(open(mMasterKeyEntry.getKeyBlobPath().c_str(),
+                                      O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
     if (out < 0) {
         return ResponseCode::SYSTEM_ERROR;
     }
@@ -124,7 +131,7 @@
     }
     if (outLength != length) {
         ALOGW("blob not fully written %zu != %zu", outLength, length);
-        unlink(mMasterKeyFile);
+        unlink(mMasterKeyEntry.getKeyBlobPath().c_str());
         return ResponseCode::SYSTEM_ERROR;
     }
     return ResponseCode::NO_ERROR;
@@ -134,11 +141,15 @@
     uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
     generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, mSalt);
     Blob masterKeyBlob(mMasterKey, sizeof(mMasterKey), mSalt, sizeof(mSalt), TYPE_MASTER_KEY);
-    return masterKeyBlob.writeBlob(mMasterKeyFile, passwordKey, STATE_NO_ERROR, entropy);
+    auto lockedEntry = LockedKeyBlobEntry::get(mMasterKeyEntry);
+    return lockedEntry.writeBlobs(masterKeyBlob, {}, passwordKey, STATE_NO_ERROR, entropy);
 }
 
 ResponseCode UserState::readMasterKey(const android::String8& pw, Entropy* entropy) {
-    int in = TEMP_FAILURE_RETRY(open(mMasterKeyFile, O_RDONLY));
+
+    auto lockedEntry = LockedKeyBlobEntry::get(mMasterKeyEntry);
+
+    int in = TEMP_FAILURE_RETRY(open(mMasterKeyEntry.getKeyBlobPath().c_str(), O_RDONLY));
     if (in < 0) {
         return ResponseCode::SYSTEM_ERROR;
     }
@@ -159,8 +170,10 @@
     }
     uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
     generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, salt);
-    Blob masterKeyBlob(rawBlob);
-    ResponseCode response = masterKeyBlob.readBlob(mMasterKeyFile, passwordKey, STATE_NO_ERROR);
+    Blob masterKeyBlob, dummyBlob;
+    ResponseCode response;
+    std::tie(response, masterKeyBlob, dummyBlob) =
+        lockedEntry.readBlobs(passwordKey, STATE_NO_ERROR);
     if (response == ResponseCode::SYSTEM_ERROR) {
         return response;
     }
@@ -198,7 +211,7 @@
 }
 
 bool UserState::reset() {
-    DIR* dir = opendir(getUserDirName());
+    DIR* dir = opendir(mMasterKeyEntry.user_dir().c_str());
     if (!dir) {
         // If the directory doesn't exist then nothing to do.
         if (errno == ENOENT) {
@@ -254,3 +267,37 @@
 void UserState::setupMasterKeys() {
     setState(STATE_NO_ERROR);
 }
+
+LockedUserState<UserState> UserStateDB::getUserState(uid_t userId) {
+    std::unique_lock<std::mutex> lock(locked_state_mutex_);
+    decltype(mMasterKeys.begin()) it;
+    bool inserted;
+    std::tie(it, inserted) = mMasterKeys.emplace(userId, userId);
+    if (inserted) {
+        if (!it->second.initialize()) {
+            /* There's not much we can do if initialization fails. Trying to
+             * unlock the keystore for that user will fail as well, so any
+             * subsequent request for this user will just return SYSTEM_ERROR.
+             */
+            ALOGE("User initialization failed for %u; subsequent operations will fail", userId);
+        }
+    }
+    return get(std::move(lock), &it->second);
+}
+
+LockedUserState<UserState> UserStateDB::getUserStateByUid(uid_t uid) {
+    return getUserState(get_user_id(uid));
+}
+
+LockedUserState<const UserState> UserStateDB::getUserState(uid_t userId) const {
+    std::unique_lock<std::mutex> lock(locked_state_mutex_);
+    auto it = mMasterKeys.find(userId);
+    if (it == mMasterKeys.end()) return {};
+    return get(std::move(lock), &it->second);
+}
+
+LockedUserState<const UserState> UserStateDB::getUserStateByUid(uid_t uid) const {
+    return getUserState(get_user_id(uid));
+}
+
+}  // namespace keystore
diff --git a/keystore/user_state.h b/keystore/user_state.h
index c28f7b8..365941e 100644
--- a/keystore/user_state.h
+++ b/keystore/user_state.h
@@ -25,19 +25,32 @@
 
 #include <keystore/keystore.h>
 
+#include "blob.h"
 #include "entropy.h"
+#include "keystore_utils.h"
+
+#include <android-base/logging.h>
+#include <condition_variable>
+#include <keystore/keystore_concurrency.h>
+#include <mutex>
+#include <set>
+
+namespace keystore {
+
+class UserState;
+
+template <typename UserState> using LockedUserState = ProxyLock<UnlockProxyLockHelper<UserState>>;
 
 class UserState {
   public:
     explicit UserState(uid_t userId);
-    ~UserState();
 
     bool initialize();
 
     uid_t getUserId() const { return mUserId; }
-    const char* getUserDirName() const { return mUserDir; }
+    const std::string& getUserDirName() const { return mMasterKeyEntry.user_dir(); }
 
-    const char* getMasterKeyFileName() const { return mMasterKeyFile; }
+    std::string getMasterKeyFileName() const { return mMasterKeyEntry.getKeyBlobPath(); }
 
     void setState(State state);
     State getState() const { return mState; }
@@ -49,15 +62,18 @@
 
     ResponseCode initialize(const android::String8& pw, Entropy* entropy);
 
-    ResponseCode copyMasterKey(UserState* src);
-    ResponseCode copyMasterKeyFile(UserState* src);
+    ResponseCode copyMasterKey(LockedUserState<UserState>* src);
+    ResponseCode copyMasterKeyFile(LockedUserState<UserState>* src);
     ResponseCode writeMasterKey(const android::String8& pw, Entropy* entropy);
     ResponseCode readMasterKey(const android::String8& pw, Entropy* entropy);
 
-    auto& getEncryptionKey() const { return mMasterKey; }
+    const uint8_t* getEncryptionKey() const { return &mMasterKey[0]; }
 
     bool reset();
 
+    bool operator<(const UserState& rhs) const;
+    bool operator<(uid_t userId) const;
+
   private:
     static const int MASTER_KEY_SIZE_BYTES = 16;
     static const int MASTER_KEY_SIZE_BITS = MASTER_KEY_SIZE_BYTES * 8;
@@ -71,11 +87,9 @@
     bool generateMasterKey(Entropy* entropy);
     void setupMasterKeys();
 
+    KeyBlobEntry mMasterKeyEntry;
+
     uid_t mUserId;
-
-    char* mUserDir;
-    char* mMasterKeyFile;
-
     State mState;
     int8_t mRetry;
 
@@ -83,4 +97,36 @@
     uint8_t mSalt[SALT_SIZE];
 };
 
+bool operator<(uid_t userId, const UserState& rhs);
+
+class UserStateDB {
+  public:
+    LockedUserState<UserState> getUserState(uid_t userId);
+    LockedUserState<UserState> getUserStateByUid(uid_t uid);
+    LockedUserState<const UserState> getUserState(uid_t userId) const;
+    LockedUserState<const UserState> getUserStateByUid(uid_t uid) const;
+
+  private:
+    mutable std::set<const UserState*> locked_state_;
+    mutable std::mutex locked_state_mutex_;
+    mutable std::condition_variable locked_state_mutex_cond_var_;
+
+    template <typename UserState>
+    LockedUserState<UserState> get(std::unique_lock<std::mutex> lock, UserState* entry) const {
+        locked_state_mutex_cond_var_.wait(
+            lock, [&] { return locked_state_.find(entry) == locked_state_.end(); });
+        locked_state_.insert(entry);
+        return {entry, [&](UserState* entry) {
+                    std::unique_lock<std::mutex> lock(locked_state_mutex_);
+                    locked_state_.erase(entry);
+                    lock.unlock();
+                    locked_state_mutex_cond_var_.notify_all();
+                }};
+    }
+
+    std::map<uid_t, UserState> mMasterKeys;
+};
+
+}  //  namespace keystore
+
 #endif  // KEYSTORE_USER_STATE_H_