Merge "Add generated form AIDL interface sources."
diff --git a/keystore/Android.bp b/keystore/Android.bp
index b881757..45b721b 100644
--- a/keystore/Android.bp
+++ b/keystore/Android.bp
@@ -34,8 +34,9 @@
         "blob.cpp",
         "confirmation_manager.cpp",
         "grant_store.cpp",
-        "key_config.proto",
-        "key_proto_handler.cpp",
+        "key_creation_log_handler.cpp",
+        "key_operation_log_handler.cpp",
+        "key_attestation_log_handler.cpp",
         "key_store_service.cpp",
         "keyblob_utils.cpp",
         "keymaster_enforcement.cpp",
@@ -44,8 +45,6 @@
         "keystore_utils.cpp",
         "legacy_keymaster_device_wrapper.cpp",
         "operation.cpp",
-        "operation_config.proto",
-        "operation_proto_handler.cpp",
         "permissions.cpp",
         "user_state.cpp",
     ],
@@ -74,6 +73,7 @@
         "libservices",
         "libsoftkeymasterdevice",
         "libutils",
+        "libstatslog",
     ],
     init_rc: ["keystore.rc"],
     aidl: {
diff --git a/keystore/include/keystore/keystore.h b/keystore/include/keystore/keystore.h
index 3aed8c2..f840eb7 100644
--- a/keystore/include/keystore/keystore.h
+++ b/keystore/include/keystore/keystore.h
@@ -45,6 +45,21 @@
     OP_AUTH_NEEDED = 15,  // Auth is needed for this operation before it can be used.
     KEY_ALREADY_EXISTS = 16,
     KEY_PERMANENTLY_INVALIDATED = 17,
+
+    /**
+     * Following three response codes are for logging purposes only.
+     * The operations are logged at the end of the life cycle of an operation handle,
+     * along with the reason for the end of the operation handle. For the operations
+     * that fail in update and finish, the reason for failure is available with
+     * the above response codes.
+     * For the operations that are aborted in three different ways, the reason
+     * for aborting is not available. The following enum values define the
+     * three ways an operation can get aborted.
+     */
+    ABORT_CALLED = 18,
+    PRUNED = 19,
+    BINDER_DIED = 20,
+
 };
 
 /*
diff --git a/keystore/key_proto_handler.h b/keystore/key_attestation_log_handler.cpp
similarity index 66%
copy from keystore/key_proto_handler.h
copy to keystore/key_attestation_log_handler.cpp
index a2f6a24..34c76a3 100644
--- a/keystore/key_proto_handler.h
+++ b/keystore/key_attestation_log_handler.cpp
@@ -13,17 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-#ifndef KEYSTORE_KEY_PROTO_HANDLER_H_
-#define KEYSTORE_KEY_PROTO_HANDLER_H_
-
-#include <keystore/keystore_hidl_support.h>
-
+#include <statslog.h>
 namespace keystore {
 
-void uploadKeyCharacteristicsAsProto(const hidl_vec<KeyParameter>& keyParams,
-                                     bool wasCreationSuccessful);
+void logKeystoreKeyAttestationEvent(bool wasSuccessful, int32_t errorCode) {
+    android::util::stats_write(android::util::KEYSTORE_KEY_EVENT_REPORTED,
+                               android::util::KEYSTORE_KEY_EVENT_REPORTED__TYPE__KEY_ATTESTATION,
+                               wasSuccessful, errorCode);
+}
 
-}  // namespace keystore
-
-#endif  // KEYSTORE_KEY_PROTO_HANDLER_H_
+}  // namespace keystore
\ No newline at end of file
diff --git a/keystore/key_proto_handler.h b/keystore/key_attestation_log_handler.h
similarity index 66%
copy from keystore/key_proto_handler.h
copy to keystore/key_attestation_log_handler.h
index a2f6a24..e69e667 100644
--- a/keystore/key_proto_handler.h
+++ b/keystore/key_attestation_log_handler.h
@@ -14,16 +14,13 @@
  * limitations under the License.
  */
 
-#ifndef KEYSTORE_KEY_PROTO_HANDLER_H_
-#define KEYSTORE_KEY_PROTO_HANDLER_H_
-
-#include <keystore/keystore_hidl_support.h>
+#ifndef _KEY_ATTESTATION_LOG_HANDLER_H_
+#define _KEY_ATTESTATION_LOG_HANDLER_H_
 
 namespace keystore {
 
-void uploadKeyCharacteristicsAsProto(const hidl_vec<KeyParameter>& keyParams,
-                                     bool wasCreationSuccessful);
+void logKeystoreKeyAttestationEvent(bool wasSuccessful, int32_t errorCode);
 
-}  // namespace keystore
+}
 
-#endif  // KEYSTORE_KEY_PROTO_HANDLER_H_
+#endif  //_KEY_ATTESTATION_LOG_HANDLER_H_
\ No newline at end of file
diff --git a/keystore/key_config.proto b/keystore/key_config.proto
deleted file mode 100644
index 0b1a398..0000000
--- a/keystore/key_config.proto
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-syntax = "proto2";
-
-package keystore;
-
-option optimize_for = LITE_RUNTIME;
-
-message KeyConfig {
-  // What type of encryption algorithm is this key being generated/imported for
-  // e.g. AES, RSA, etc
-  optional string algorithm = 1;
-
-  // Size of the key being generated/imported
-  optional int32 key_size = 2;
-
-  // Log whether the key was generated, imported, securely imported, or derived.
-  optional string origin = 3;
-
-  // What auth types does this key require? If none, then no auth required.
-  optional string user_auth_type = 4;
-
-  // If user authentication is required, is the requirement time based? If it
-  // is not time based then this field will not be used and the key is per
-  // operation. Per operation keys must be user authenticated on each usage.
-  optional int32 user_auth_key_timeout = 5;
-
-  // Track which padding modes this key supports.
-  repeated string padding = 6;
-
-  // Track which digests this key supports
-  repeated string digest = 7;
-
-  // Check what block mode is being used depending on the mode of encryption
-  repeated string block_mode = 8;
-
-  // Was the key generated/imported successfully?
-  optional bool was_creation_successful = 9;
-
-  // What purposes can this key be used for?
-  repeated string purpose = 10;
-
-  // Which ec curve was selected if elliptic curve cryptography is in use
-  optional string ec_curve = 11;
-
-  // Standalone or is a file system required
-  optional string key_blob_usage_reqs = 12;
-}
diff --git a/keystore/key_creation_log_handler.cpp b/keystore/key_creation_log_handler.cpp
new file mode 100644
index 0000000..d846257
--- /dev/null
+++ b/keystore/key_creation_log_handler.cpp
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 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 "KeystoreOperation"
+
+#include "key_creation_log_handler.h"
+#include <statslog.h>
+
+namespace keystore {
+
+template <typename Tag>
+int32_t getEnumTagValue(const AuthorizationSet& authorization_set, Tag tag) {
+    auto tagValue = authorization_set.GetTagValue(tag);
+    if (tagValue.isOk()) {
+        static_assert(sizeof(decltype(tagValue.value())) <= sizeof(int32_t),
+                      "Tag type value will be truncated, if cast to int32_t");
+        return static_cast<int32_t>(tagValue.value());
+    }
+    // Usually, if the value is not present, 0 is set. However, since 0 is a valid
+    // enum value, -1 is set for single enum fields.
+    return -1;
+}
+
+int32_t generateBitMapForPaddingModeValues(const AuthorizationSet& authorization_set) {
+    int32_t bitMap = 0;
+    int32_t tagValueCount = authorization_set.GetTagCount(TAG_PADDING);
+    if (tagValueCount == 0) {
+        // unlike in the single enum fields, if no value is provided,
+        // 0 is set for the bitmap
+        return bitMap;
+    }
+    int current_offset = -1;
+    while (tagValueCount > 0) {
+        current_offset = authorization_set.find(TAG_PADDING, current_offset);
+        KeyParameter keyParam = authorization_set[current_offset];
+        auto tagValue = accessTagValue(TAG_PADDING, keyParam);
+        switch (tagValue) {
+        case PaddingMode::NONE:
+            bitMap |= (1 << NONE_BIT_POS);
+            break;
+        case PaddingMode::RSA_OAEP:
+            bitMap |= (1 << PaddingModeBitPosition::RSA_OAEP_BIT_POS);
+            break;
+        case PaddingMode::RSA_PSS:
+            bitMap |= (1 << PaddingModeBitPosition::RSA_PSS_BIT_POS);
+            break;
+        case PaddingMode::RSA_PKCS1_1_5_ENCRYPT:
+            bitMap |= (1 << PaddingModeBitPosition::RSA_PKCS1_1_5_ENCRYPT_BIT_POS);
+            break;
+        case PaddingMode::RSA_PKCS1_1_5_SIGN:
+            bitMap |= (1 << PaddingModeBitPosition::RSA_PKCS1_1_5_SIGN_BIT_POS);
+            break;
+        case PaddingMode::PKCS7:
+            bitMap |= (1 << PaddingModeBitPosition::PKCS7_BIT_POS);
+            break;
+        default:
+            break;
+        }
+        tagValueCount -= 1;
+    }
+    return bitMap;
+}
+
+int32_t generateBitMapForDigestValues(const AuthorizationSet& authorization_set) {
+    int32_t bitMap = 0;
+    int32_t tagValueCount = authorization_set.GetTagCount(TAG_DIGEST);
+    if (tagValueCount == 0) {
+        // unlike in the single enum fields, if no value is provided,
+        // 0 is set for the bitmap
+        return bitMap;
+    }
+    int current_offset = -1;
+    while (tagValueCount > 0) {
+        current_offset = authorization_set.find(TAG_DIGEST, current_offset);
+        KeyParameter keyParam = authorization_set[current_offset];
+        auto tagValue = accessTagValue(TAG_DIGEST, keyParam);
+        switch (tagValue) {
+        case Digest::NONE:
+            bitMap |= (1 << NONE_BIT_POS);
+            break;
+        case Digest::MD5:
+            bitMap |= (1 << DigestBitPosition::MD5_BIT_POS);
+            break;
+        case Digest::SHA1:
+            bitMap |= (1 << DigestBitPosition::SHA1_BIT_POS);
+            break;
+        case Digest::SHA_2_224:
+            bitMap |= (1 << DigestBitPosition::SHA_2_224_BIT_POS);
+            break;
+        case Digest::SHA_2_256:
+            bitMap |= (1 << DigestBitPosition::SHA_2_256_BIT_POS);
+            break;
+        case Digest::SHA_2_384:
+            bitMap |= (1 << DigestBitPosition::SHA_2_384_BIT_POS);
+            break;
+        case Digest::SHA_2_512:
+            bitMap |= (1 << DigestBitPosition::SHA_2_512_BIT_POS);
+            break;
+        default:
+            break;
+        }
+        tagValueCount -= 1;
+    }
+    return bitMap;
+}
+
+int32_t generateBitMapForBlockModeValues(const AuthorizationSet& authorization_set) {
+    int32_t bitMap = 0;
+    int32_t tagValueCount = authorization_set.GetTagCount(TAG_BLOCK_MODE);
+    if (tagValueCount == 0) {
+        // unlike in the single enum fields, if no value is provided,
+        // 0 is set for the bitmap
+        return bitMap;
+    }
+    int current_offset = -1;
+    while (tagValueCount > 0) {
+        current_offset = authorization_set.find(TAG_BLOCK_MODE, current_offset);
+        KeyParameter keyParam = authorization_set[current_offset];
+        auto tagValue = accessTagValue(TAG_BLOCK_MODE, keyParam);
+        switch (tagValue) {
+        case BlockMode::ECB:
+            bitMap |= (1 << BlockModeBitPosition::ECB_BIT_POS);
+            break;
+        case BlockMode::CBC:
+            bitMap |= (1 << BlockModeBitPosition::CBC_BIT_POS);
+            break;
+        case BlockMode::CTR:
+            bitMap |= (1 << BlockModeBitPosition::CTR_BIT_POS);
+            break;
+        case BlockMode::GCM:
+            bitMap |= (1 << BlockModeBitPosition::GCM_BIT_POS);
+            break;
+        default:
+            break;
+        }
+        tagValueCount -= 1;
+    }
+    return bitMap;
+}
+
+int32_t generateBitMapForKeyPurposeValues(const AuthorizationSet& authorization_set) {
+    int32_t bitMap = 0;
+    int32_t tagValueCount = authorization_set.GetTagCount(TAG_PURPOSE);
+    if (tagValueCount == 0) {
+        // unlike in the single enum fields, if no value is provided,
+        // 0 is set for the bitmap
+        return bitMap;
+    }
+    int current_offset = -1;
+    while (tagValueCount > 0) {
+        current_offset = authorization_set.find(TAG_PURPOSE, current_offset);
+        KeyParameter keyParam = authorization_set[current_offset];
+        auto tagValue = accessTagValue(TAG_PURPOSE, keyParam);
+        switch (tagValue) {
+        case KeyPurpose::ENCRYPT:
+            bitMap |= (1 << KeyPurposeBitPosition::ENCRYPT_BIT_POS);
+            break;
+        case KeyPurpose::DECRYPT:
+            bitMap |= (1 << KeyPurposeBitPosition::DECRYPT_BIT_POS);
+            break;
+        case KeyPurpose::SIGN:
+            bitMap |= (1 << KeyPurposeBitPosition::SIGN_BIT_POS);
+            break;
+        case KeyPurpose::VERIFY:
+            bitMap |= (1 << KeyPurposeBitPosition::VERIFY_BIT_POS);
+            break;
+        case KeyPurpose::WRAP_KEY:
+            bitMap |= (1 << KeyPurposeBitPosition::WRAP_KEY_BIT_POS);
+            break;
+        default:
+            break;
+        }
+        tagValueCount -= 1;
+    }
+    return bitMap;
+}
+
+void logKeystoreKeyCreationEvent(const hidl_vec<KeyParameter>& keyParams,
+                                 bool wasCreationSuccessful, int32_t errorCode) {
+    AuthorizationSet authorization_set(keyParams);
+    authorization_set.Deduplicate();
+
+    android::util::stats_write(android::util::KEYSTORE_KEY_EVENT_REPORTED,
+                               getEnumTagValue(authorization_set, TAG_ALGORITHM),
+                               getEnumTagValue(authorization_set, TAG_KEY_SIZE),
+                               getEnumTagValue(authorization_set, TAG_ORIGIN),
+                               getEnumTagValue(authorization_set, TAG_USER_AUTH_TYPE),
+                               getEnumTagValue(authorization_set, TAG_AUTH_TIMEOUT),
+                               generateBitMapForPaddingModeValues(authorization_set),
+                               generateBitMapForDigestValues(authorization_set),
+                               generateBitMapForBlockModeValues(authorization_set),
+                               generateBitMapForKeyPurposeValues(authorization_set),
+                               getEnumTagValue(authorization_set, TAG_EC_CURVE),
+                               getEnumTagValue(authorization_set, TAG_BLOB_USAGE_REQUIREMENTS),
+                               android::util::KEYSTORE_KEY_EVENT_REPORTED__TYPE__KEY_CREATION,
+                               wasCreationSuccessful, errorCode);
+}
+
+}  // namespace keystore
diff --git a/keystore/key_creation_log_handler.h b/keystore/key_creation_log_handler.h
new file mode 100644
index 0000000..a314eb1
--- /dev/null
+++ b/keystore/key_creation_log_handler.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 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 KEY_CREATION_LOG_HANDLER_H_
+#define KEY_CREATION_LOG_HANDLER_H_
+
+#include <keystore/keystore_hidl_support.h>
+
+namespace keystore {
+
+/**
+ * Following enums are defined as a part of the workaround to log the repeated
+ * values of ENUM_REP type. The workaround is to represent the repeated values
+ * of ENUM_REP type as a bitmap and the following enums define their positions
+ * in the bitmap.
+ */
+
+enum PaddingModeBitPosition : int32_t {
+    RSA_OAEP_BIT_POS = 1,
+    RSA_PSS_BIT_POS = 2,
+    RSA_PKCS1_1_5_ENCRYPT_BIT_POS = 3,
+    RSA_PKCS1_1_5_SIGN_BIT_POS = 4,
+    PKCS7_BIT_POS = 5,
+};
+
+enum DigestBitPosition : int32_t {
+    MD5_BIT_POS = 1,
+    SHA1_BIT_POS = 2,
+    SHA_2_224_BIT_POS = 3,
+    SHA_2_256_BIT_POS = 4,
+    SHA_2_384_BIT_POS = 5,
+    SHA_2_512_BIT_POS = 6,
+};
+
+enum BlockModeBitPosition : int32_t {
+    ECB_BIT_POS = 1,
+    CBC_BIT_POS = 2,
+    CTR_BIT_POS = 3,
+    GCM_BIT_POS = 4,
+};
+
+enum KeyPurposeBitPosition : int32_t {
+    ENCRYPT_BIT_POS = 1,
+    DECRYPT_BIT_POS = 2,
+    SIGN_BIT_POS = 3,
+    VERIFY_BIT_POS = 4,
+    WRAP_KEY_BIT_POS = 5,
+};
+
+// None is an enum value for digest and a deprecated value for padding mode
+const int32_t NONE_BIT_POS = 0;
+
+void logKeystoreKeyCreationEvent(const hidl_vec<KeyParameter>& keyParams,
+                                 bool wasCreationSuccessful, int32_t errorCode);
+
+}  // namespace keystore
+
+#endif  // KEY_CREATION_LOG_HANDLER_H_
diff --git a/keystore/key_operation_log_handler.cpp b/keystore/key_operation_log_handler.cpp
new file mode 100644
index 0000000..140d5a7
--- /dev/null
+++ b/keystore/key_operation_log_handler.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 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 "KeystoreOperation"
+
+#include "key_operation_log_handler.h"
+#include "key_creation_log_handler.h"
+
+#include <keystore/keystore_hidl_support.h>
+#include <statslog.h>
+
+namespace keystore {
+
+template <typename Tag>
+int32_t getOptionalEnumTagValue(const AuthorizationSet& authorization_set, Tag tag) {
+    auto tagValue = authorization_set.GetTagValue(tag);
+    if (tagValue.isOk()) {
+        static_assert(sizeof(decltype(tagValue.value())) <= sizeof(int32_t),
+                      "Tag type value will be truncated, if cast to int32_t");
+        return static_cast<int32_t>(tagValue.value());
+    }
+    //-1 is an invalid value for all enum types.
+    return -1;
+}
+
+int32_t generateBitMapForPaddingModeValue(const AuthorizationSet& authorization_set) {
+    auto tagValue = authorization_set.GetTagValue(TAG_PADDING);
+    if (tagValue.isOk()) {
+        auto value = tagValue.value();
+        switch (value) {
+        case PaddingMode::NONE:
+            return (1 << NONE_BIT_POS);
+        case PaddingMode::RSA_OAEP:
+            return (1 << PaddingModeBitPosition::RSA_OAEP_BIT_POS);
+        case PaddingMode::RSA_PSS:
+            return (1 << PaddingModeBitPosition::RSA_PSS_BIT_POS);
+        case PaddingMode::RSA_PKCS1_1_5_ENCRYPT:
+            return (1 << PaddingModeBitPosition::RSA_PKCS1_1_5_ENCRYPT_BIT_POS);
+        case PaddingMode::RSA_PKCS1_1_5_SIGN:
+            return (1 << PaddingModeBitPosition::RSA_PKCS1_1_5_SIGN_BIT_POS);
+        case PaddingMode::PKCS7:
+            return (1 << PaddingModeBitPosition::PKCS7_BIT_POS);
+        default:
+            break;
+        }
+    }
+    // unlike in the single enum fields, if no value is provided,
+    // 0 is set for the bitmap
+    return 0;
+}
+
+int32_t generateBitMapForDigestValue(const AuthorizationSet& authorization_set) {
+    auto tagValue = authorization_set.GetTagValue(TAG_DIGEST);
+    if (tagValue.isOk()) {
+        auto value = tagValue.value();
+        switch (value) {
+        case Digest::NONE:
+            return (1 << NONE_BIT_POS);
+        case Digest::MD5:
+            return (1 << DigestBitPosition::MD5_BIT_POS);
+        case Digest::SHA1:
+            return (1 << DigestBitPosition::SHA1_BIT_POS);
+        case Digest::SHA_2_224:
+            return (1 << DigestBitPosition::SHA_2_224_BIT_POS);
+        case Digest::SHA_2_256:
+            return (1 << DigestBitPosition::SHA_2_256_BIT_POS);
+        case Digest::SHA_2_384:
+            return (1 << DigestBitPosition::SHA_2_384_BIT_POS);
+        case Digest::SHA_2_512:
+            return (1 << DigestBitPosition::SHA_2_512_BIT_POS);
+        default:
+            break;
+        }
+    }
+    // unlike in the single enum fields, if no value is provided,
+    // 0 is set for the bitmap
+    return 0;
+}
+
+int32_t generateBitMapForBlockModeValue(const AuthorizationSet& authorization_set) {
+    auto tagValue = authorization_set.GetTagValue(TAG_BLOCK_MODE);
+    if (tagValue.isOk()) {
+        auto value = tagValue.value();
+        switch (value) {
+        case BlockMode::ECB:
+            return (1 << BlockModeBitPosition::ECB_BIT_POS);
+        case BlockMode::CBC:
+            return (1 << BlockModeBitPosition::CBC_BIT_POS);
+        case BlockMode::CTR:
+            return (1 << BlockModeBitPosition::CTR_BIT_POS);
+        case BlockMode::GCM:
+            return (1 << BlockModeBitPosition::GCM_BIT_POS);
+        default:
+            break;
+        }
+    }
+    // unlike in the single enum fields, if no value is provided,
+    // 0 is set for the bitmap
+    return 0;
+}
+
+void logKeystoreKeyOperationEvent(const Operation& op, bool wasOperationSuccessful,
+                                  int32_t responseCode) {
+    AuthorizationSet authorization_set(op.characteristics.softwareEnforced);
+    authorization_set.Union(op.characteristics.hardwareEnforced);
+    AuthorizationSet operation_params(op.params);
+
+    android::util::stats_write(
+        android::util::KEYSTORE_KEY_EVENT_REPORTED,
+        getOptionalEnumTagValue(authorization_set, TAG_ALGORITHM),
+        getOptionalEnumTagValue(authorization_set, TAG_KEY_SIZE),
+        getOptionalEnumTagValue(authorization_set, TAG_ORIGIN),
+        getOptionalEnumTagValue(authorization_set, TAG_USER_AUTH_TYPE),
+        getOptionalEnumTagValue(authorization_set, TAG_AUTH_TIMEOUT),
+        generateBitMapForPaddingModeValue(operation_params),
+        generateBitMapForDigestValue(operation_params),
+        generateBitMapForBlockModeValue(operation_params), static_cast<int32_t>(op.purpose),
+        getOptionalEnumTagValue(authorization_set, TAG_EC_CURVE),
+        getOptionalEnumTagValue(authorization_set, TAG_BLOB_USAGE_REQUIREMENTS),
+        android::util::KEYSTORE_KEY_EVENT_REPORTED__TYPE__KEY_OPERATION, wasOperationSuccessful,
+        responseCode);
+}
+
+}  // namespace keystore
diff --git a/keystore/key_proto_handler.h b/keystore/key_operation_log_handler.h
similarity index 68%
rename from keystore/key_proto_handler.h
rename to keystore/key_operation_log_handler.h
index a2f6a24..efd3f00 100644
--- a/keystore/key_proto_handler.h
+++ b/keystore/key_operation_log_handler.h
@@ -14,16 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef KEYSTORE_KEY_PROTO_HANDLER_H_
-#define KEYSTORE_KEY_PROTO_HANDLER_H_
+#ifndef KEY_OPERATION_LOG_HANDLER_H_
+#define KEY_OPERATION_LOG_HANDLER_H_
 
-#include <keystore/keystore_hidl_support.h>
+#include "operation_struct.h"
 
 namespace keystore {
 
-void uploadKeyCharacteristicsAsProto(const hidl_vec<KeyParameter>& keyParams,
-                                     bool wasCreationSuccessful);
+void logKeystoreKeyOperationEvent(const Operation& op, bool wasSuccessful, int32_t errorCode);
 
 }  // namespace keystore
 
-#endif  // KEYSTORE_KEY_PROTO_HANDLER_H_
+#endif  // KEY_OPERATION_LOG_HANDLER_H_
diff --git a/keystore/key_proto_handler.cpp b/keystore/key_proto_handler.cpp
deleted file mode 100644
index f8400af..0000000
--- a/keystore/key_proto_handler.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 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 "KeystoreOperation"
-
-#include "key_proto_handler.h"
-
-#include <android/os/DropBoxManager.h>
-#include <google/protobuf/message_lite.h>
-#include <keymasterV4_1/Keymaster.h>
-#include <keystore/keymaster_types.h>
-#include <utils/String16.h>
-#include <utils/StrongPointer.h>
-
-#include "key_config.pb.h"
-
-namespace keystore {
-
-void checkEnforcedCharacteristics(const hidl_vec<KeyParameter>& keyParams, KeyConfig* keyConfig) {
-    for (auto& keyParam : keyParams) {
-        switch (keyParam.tag) {
-        case Tag::PURPOSE:
-            keyConfig->add_purpose(toString(accessTagValue(TAG_PURPOSE, keyParam)));
-            break;
-        case Tag::ALGORITHM:
-            keyConfig->set_algorithm(toString(accessTagValue(TAG_ALGORITHM, keyParam)));
-            break;
-        case Tag::KEY_SIZE:
-            keyConfig->set_key_size(accessTagValue(TAG_KEY_SIZE, keyParam));
-            break;
-        case Tag::BLOCK_MODE:
-            keyConfig->add_block_mode(toString(accessTagValue(TAG_BLOCK_MODE, keyParam)));
-            break;
-        case Tag::PADDING:
-            keyConfig->add_padding(toString(accessTagValue(TAG_PADDING, keyParam)));
-            break;
-        case Tag::DIGEST:
-            keyConfig->add_digest(toString(accessTagValue(TAG_DIGEST, keyParam)));
-            break;
-        case Tag::EC_CURVE:
-            keyConfig->set_ec_curve(toString(accessTagValue(TAG_EC_CURVE, keyParam)));
-            break;
-        case Tag::AUTH_TIMEOUT:
-            keyConfig->set_user_auth_key_timeout(accessTagValue(TAG_AUTH_TIMEOUT, keyParam));
-            break;
-        case Tag::ORIGIN:
-            keyConfig->set_origin(toString(accessTagValue(TAG_ORIGIN, keyParam)));
-            break;
-        case Tag::BLOB_USAGE_REQUIREMENTS:
-            keyConfig->set_key_blob_usage_reqs(
-                toString(accessTagValue(TAG_BLOB_USAGE_REQUIREMENTS, keyParam)));
-            break;
-        case Tag::USER_AUTH_TYPE:
-            keyConfig->set_user_auth_type(toString(accessTagValue(TAG_USER_AUTH_TYPE, keyParam)));
-            break;
-        default:
-            break;
-        }
-    }
-}
-
-void uploadKeyCharacteristicsAsProto(const hidl_vec<KeyParameter>& keyParams,
-                                     bool wasCreationSuccessful) {
-    KeyConfig keyConfig;
-    checkEnforcedCharacteristics(keyParams, &keyConfig);
-    android::sp<android::os::DropBoxManager> dropbox(new android::os::DropBoxManager());
-    keyConfig.set_was_creation_successful(wasCreationSuccessful);
-
-    size_t size = keyConfig.ByteSize();
-    auto data = std::make_unique<uint8_t[]>(size);
-    keyConfig.SerializeWithCachedSizesToArray(data.get());
-    dropbox->addData(android::String16("keymaster"), data.get(), size, 0);
-}
-
-}  // namespace keystore
diff --git a/keystore/key_store_service.cpp b/keystore/key_store_service.cpp
index 583f5b6..4e5bc48 100644
--- a/keystore/key_store_service.cpp
+++ b/keystore/key_store_service.cpp
@@ -41,7 +41,7 @@
 #include <keymasterV4_0/keymaster_utils.h>
 
 #include "defaults.h"
-#include "key_proto_handler.h"
+#include "key_attestation_log_handler.h"
 #include "keystore_keymaster_enforcement.h"
 #include "keystore_utils.h"
 #include <keystore/keystore_attestation_id.h>
@@ -1118,6 +1118,10 @@
 
     AuthorizationSet mutableParams = params.getParameters();
     KeyStoreServiceReturnCode rc = updateParamsForAttestation(callingUid, &mutableParams);
+
+    auto logErrorOnReturn = android::base::make_scope_guard(
+        [&] { logKeystoreKeyAttestationEvent(false /*wasSuccessful*/, rc.getErrorCode()); });
+
     if (!rc.isOk()) {
         return AIDL_RETURN(rc);
     }
@@ -1134,6 +1138,8 @@
         return AIDL_RETURN(rc);
     }
 
+    logErrorOnReturn.Disable();
+
     auto dev = mKeyStore->getDevice(keyBlob);
     auto hidlKey = blob2hidlVec(keyBlob);
     dev->attestKey(
@@ -1142,13 +1148,18 @@
                   std::tuple<ErrorCode, hidl_vec<hidl_vec<uint8_t>>>&& hidlResult) {
             auto& [ret, certChain] = hidlResult;
             if (!rc.isOk()) {
+                logKeystoreKeyAttestationEvent(false /*wasSuccessful*/,
+                                               static_cast<int32_t>(ResponseCode::SYSTEM_ERROR));
                 cb->onFinished(KeyStoreServiceReturnCode(ResponseCode::SYSTEM_ERROR), {});
             } else if (ret != ErrorCode::OK) {
+                KeyStoreServiceReturnCode ksrc(ret);
+                logKeystoreKeyAttestationEvent(false /*wasSuccessful*/, ksrc.getErrorCode());
                 dev->logIfKeymasterVendorError(ret);
-                cb->onFinished(KeyStoreServiceReturnCode(ret), {});
+                cb->onFinished(ksrc, {});
             } else {
-                cb->onFinished(KeyStoreServiceReturnCode(ret),
-                               KeymasterCertificateChain(std::move(certChain)));
+                KeyStoreServiceReturnCode ksrc(ret);
+                logKeystoreKeyAttestationEvent(true /*wasSuccessful*/, ksrc.getErrorCode());
+                cb->onFinished(ksrc, KeymasterCertificateChain(std::move(certChain)));
             }
         });
 
diff --git a/keystore/keymaster_worker.cpp b/keystore/keymaster_worker.cpp
index 911815e..7481a1e 100644
--- a/keystore/keymaster_worker.cpp
+++ b/keystore/keymaster_worker.cpp
@@ -29,7 +29,7 @@
 #include "KeyStore.h"
 #include "keymaster_enforcement.h"
 
-#include "key_proto_handler.h"
+#include "key_creation_log_handler.h"
 #include "keystore_utils.h"
 
 #include <chrono>
@@ -336,8 +336,10 @@
     return {rc, std::move(authToken)};
 }
 
-KeyStoreServiceReturnCode KeymasterWorker::abort(const sp<IBinder>& token) {
-    auto op = operationMap_.removeOperation(token, false /* wasOpSuccessful */);
+KeyStoreServiceReturnCode KeymasterWorker::abort(const sp<IBinder>& token,
+                                                 ResponseCode reason_for_abort) {
+    auto op = operationMap_.removeOperation(token, false /* wasOpSuccessful */,
+                                            static_cast<int32_t>(reason_for_abort));
     if (op) {
         keyStore_->getAuthTokenTable().MarkCompleted(op->handle);
         return KS_HANDLE_HIDL_ERROR(keymasterDevice_, keymasterDevice_->abort(op->handle));
@@ -355,7 +357,7 @@
     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);
+    auto rc = abort(oldest, ResponseCode::PRUNED);
     keyStore_->removeOperationDevice(oldest);
     if (operationMap_.getOperationCount() >= op_count_before_abort) {
         ALOGE("Failed to abort pruneable operation %p, error: %d", oldest.get(), rc.getErrorCode());
@@ -598,7 +600,7 @@
         }
 
         Finalize abort_operation_in_case_of_error([&] {
-            operationMap_.removeOperation(token, false);
+            operationMap_.removeOperation(token, false, rc.getErrorCode());
             keyStore_->getAuthTokenTable().MarkCompleted(op->handle);
             KS_HANDLE_HIDL_ERROR(keymasterDevice_, keymasterDevice_->abort(op->handle));
         });
@@ -677,7 +679,7 @@
 
         bool finished = false;
         Finalize abort_operation_in_case_of_error([&] {
-            operationMap_.removeOperation(token, finished && rc.isOk());
+            operationMap_.removeOperation(token, finished && rc.isOk(), rc.getErrorCode());
             keyStore_->getAuthTokenTable().MarkCompleted(op->handle);
             if (!finished)
                 KS_HANDLE_HIDL_ERROR(keymasterDevice_, keymasterDevice_->abort(op->handle));
@@ -745,8 +747,9 @@
 }
 
 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)); });
+    Worker::addRequest([this, CAPTURE_MOVE(token), CAPTURE_MOVE(worker_cb)]() {
+        return worker_cb(abort(token, ResponseCode::ABORT_CALLED));
+    });
 }
 
 void KeymasterWorker::verifyAuthorization(uint64_t challenge, hidl_vec<KeyParameter> params,
@@ -800,8 +803,10 @@
         // by KeyStore::getFallbackDevice()
         bool consider_fallback = securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT;
 
-        Finalize logOnFail(
-            [&] { uploadKeyCharacteristicsAsProto(keyParams, false /* wasCreationSuccessful */); });
+        Finalize logOnFail([&] {
+            logKeystoreKeyCreationEvent(keyParams, false /*wasCreationSuccessful*/,
+                                        rc.getErrorCode());
+        });
 
         KeyCharacteristics outCharacteristics;
         KeyStoreServiceReturnCode error;
@@ -870,7 +875,8 @@
 
         // log on success
         logOnFail.release();
-        uploadKeyCharacteristicsAsProto(keyParams, true /* wasCreationSuccessful */);
+        logKeystoreKeyCreationEvent(keyParams, true /*wasCreationSuccessful*/,
+                                    error.getErrorCode());
 
         return worker_cb(error, std::move(outCharacteristics));
     });
@@ -904,11 +910,13 @@
         // by KeyStore::getFallbackDevice()
         bool consider_fallback = securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT;
 
-        Finalize logOnFail(
-            [&] { uploadKeyCharacteristicsAsProto(keyParams, false /* wasCreationSuccessful */); });
+        KeyStoreServiceReturnCode error;
+        Finalize logOnFail([&] {
+            logKeystoreKeyCreationEvent(keyParams, false /*wasCreationSuccessful*/,
+                                        error.getErrorCode());
+        });
 
         KeyCharacteristics outCharacteristics;
-        KeyStoreServiceReturnCode error;
         auto hidl_cb = [&](ErrorCode ret, const hidl_vec<uint8_t>& hidlKeyBlob,
                            const KeyCharacteristics& keyCharacteristics) {
             keymasterDevice_->logIfKeymasterVendorError(ret);
@@ -975,7 +983,8 @@
 
         // log on success
         logOnFail.release();
-        uploadKeyCharacteristicsAsProto(keyParams, true /* wasCreationSuccessful */);
+        logKeystoreKeyCreationEvent(keyParams, true /*wasCreationSuccessful*/,
+                                    error.getErrorCode());
 
         return worker_cb(error, std::move(outCharacteristics));
     });
@@ -1126,7 +1135,7 @@
     Worker::addRequest([this, who]() {
         auto operations = operationMap_.getOperationsForToken(who.unsafe_get());
         for (const auto& token : operations) {
-            abort(token);
+            abort(token, ResponseCode::BINDER_DIED);
             keyStore_->removeOperationDevice(token);
         }
     });
diff --git a/keystore/keymaster_worker.h b/keystore/keymaster_worker.h
index 8e35c16..f11af29 100644
--- a/keystore/keymaster_worker.h
+++ b/keystore/keymaster_worker.h
@@ -190,7 +190,7 @@
     getAuthToken(const KeyCharacteristics& characteristics, uint64_t handle, KeyPurpose purpose,
                  bool failOnTokenMissing = true);
 
-    KeyStoreServiceReturnCode abort(const sp<IBinder>& token);
+    KeyStoreServiceReturnCode abort(const sp<IBinder>& token, ResponseCode reason_for_abort);
 
     bool pruneOperation();
 
diff --git a/keystore/operation.cpp b/keystore/operation.cpp
index 71ab340..bd4bd5e 100644
--- a/keystore/operation.cpp
+++ b/keystore/operation.cpp
@@ -16,6 +16,7 @@
 #define LOG_TAG "KeystoreOperation"
 
 #include "operation.h"
+#include "key_operation_log_handler.h"
 
 #include <algorithm>
 #include <android-base/logging.h>
@@ -58,12 +59,12 @@
 }
 
 std::shared_ptr<Operation> OperationMap::removeOperation(const sp<IBinder>& token,
-                                                         bool wasSuccessful) {
+                                                         bool wasSuccessful, int32_t responseCode) {
     auto entry = mMap.find(token);
     if (entry == mMap.end()) return {};
 
     auto op = entry->second;
-    operationUploader.uploadOpAsProto(*op, wasSuccessful);
+    logKeystoreKeyOperationEvent(*op, wasSuccessful, responseCode);
     mMap.erase(entry);
 
     auto lruEntry = std::find(mLru.begin(), mLru.end(), token);
diff --git a/keystore/operation.h b/keystore/operation.h
index ef880a7..8423db5 100644
--- a/keystore/operation.h
+++ b/keystore/operation.h
@@ -33,7 +33,6 @@
 #include <keystore/keystore_concurrency.h>
 #include <keystore/keystore_hidl_support.h>
 
-#include "operation_proto_handler.h"
 #include "operation_struct.h"
 
 namespace keystore {
@@ -57,7 +56,8 @@
                              KeyCharacteristics&& characteristics,
                              const hidl_vec<KeyParameter>& params, bool pruneable);
     std::shared_ptr<Operation> getOperation(const sp<IBinder>& token);
-    std::shared_ptr<Operation> removeOperation(const sp<IBinder>& token, bool wasSuccessful);
+    std::shared_ptr<Operation> removeOperation(const sp<IBinder>& token, bool wasSuccessful,
+                                               int32_t responseCode);
     size_t getOperationCount() const { return mMap.size(); }
     sp<IBinder> getOldestPruneableOperation();
     std::vector<sp<IBinder>> getOperationsForToken(const sp<IBinder>& appToken);
@@ -70,7 +70,6 @@
     std::list<sp<IBinder>> mLru;
     std::map<sp<IBinder>, std::vector<sp<IBinder>>> mAppTokenMap;
     IBinder::DeathRecipient* mDeathRecipient;
-    OperationProtoHandler operationUploader;
 };
 
 }  // namespace keystore
diff --git a/keystore/operation_config.proto b/keystore/operation_config.proto
deleted file mode 100644
index efbb4fe..0000000
--- a/keystore/operation_config.proto
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-syntax = "proto2";
-
-package keystore;
-
-option optimize_for = LITE_RUNTIME;
-
-// A single operation config
-message OperationConfig {
-  // What type of encryption algorithm is the key being used in the op for.
-  optional string algorithm = 1;
-
-  // Size of the key being used in this op
-  optional int32 key_size = 2;
-
-  // Log whether the key in this op was generated, imported,
-  // securely imported, or derived.
-  optional string origin = 3;
-
-  // What auth types does this op require? If none, then no auth required.
-  optional string user_auth_type = 4;
-
-  // If user authentication is required, is the requirement time based? If it
-  // is not time based then this field will not be used and the key is per
-  // operation. Per operation keys must be user authenticated on each usage.
-  optional int32 user_auth_key_timeout = 5;
-
-  // Track which padding mode was used for this operation.
-  optional string padding = 6;
-
-  // Keep track of the digest algorithm being used.
-  optional string digest = 7;
-
-  // Check what block mode is being used depending on the mode of encryption
-  optional string block_mode = 8;
-
-  // Did the operation succeed? If it didn't, this represents bugs or
-  // error cases occurring.
-  optional bool was_op_successful = 9;
-
-  // What purpose is this operation serving? Encrypt, decrypt, sign verify?
-  optional string purpose = 10;
-
-  // Which ec curve was selected if elliptic curve cryptography is in use
-  optional string ec_curve = 11;
-
-  // Standalone or is a file system required
-  optional string key_blob_usage_reqs = 12;
-}
-
-message OperationConfigEvent {
-  optional OperationConfig op_config = 1;
-
-  // counts corresponds to the number of times each op_config in the above array
-  // was recorded during the collection period.
-  optional uint32 count = 2;
-}
-
-message OperationConfigEvents {
-    repeated OperationConfigEvent op_config_events = 1;
-}
-
diff --git a/keystore/operation_proto_handler.cpp b/keystore/operation_proto_handler.cpp
deleted file mode 100644
index 3b3d3fc..0000000
--- a/keystore/operation_proto_handler.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 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 "KeystoreOperation"
-
-#include "operation_proto_handler.h"
-
-#include <android/os/DropBoxManager.h>
-#include <google/protobuf/message_lite.h>
-#include <keymasterV4_1/Keymaster.h>
-#include <keystore/keymaster_types.h>
-#include <keystore/keystore_hidl_support.h>
-#include <utils/String16.h>
-#include <utils/StrongPointer.h>
-
-using namespace std::chrono;
-
-namespace keystore {
-
-constexpr auto kCollectionTime = 1h;
-
-void determinePurpose(KeyPurpose purpose, OperationConfig* operationConfig) {
-    switch (purpose) {
-    case KeyPurpose::VERIFY:
-        operationConfig->set_purpose("verify");
-        break;
-    case KeyPurpose::ENCRYPT:
-        operationConfig->set_purpose("encrypt");
-        break;
-    case KeyPurpose::SIGN:
-        operationConfig->set_purpose("sign");
-        break;
-    case KeyPurpose::DECRYPT:
-        operationConfig->set_purpose("decrypt");
-        break;
-    case KeyPurpose::WRAP_KEY:
-        operationConfig->set_purpose("wrap");
-        break;
-    default:
-        break;
-    }
-}
-
-void checkKeyCharacteristics(const hidl_vec<KeyParameter>& characteristics,
-                             OperationConfig* operationConfig) {
-    for (auto& opParam : characteristics) {
-        switch (opParam.tag) {
-        case Tag::ALGORITHM:
-            operationConfig->set_algorithm(toString(accessTagValue(TAG_ALGORITHM, opParam)));
-            break;
-        case Tag::KEY_SIZE:
-            operationConfig->set_key_size(accessTagValue(TAG_KEY_SIZE, opParam));
-            break;
-        case Tag::EC_CURVE:
-            operationConfig->set_ec_curve(toString(accessTagValue(TAG_EC_CURVE, opParam)));
-            break;
-        case Tag::AUTH_TIMEOUT:
-            operationConfig->set_user_auth_key_timeout(accessTagValue(TAG_AUTH_TIMEOUT, opParam));
-            break;
-        case Tag::ORIGIN:
-            operationConfig->set_origin(toString(accessTagValue(TAG_ORIGIN, opParam)));
-            break;
-        case Tag::BLOB_USAGE_REQUIREMENTS:
-            operationConfig->set_key_blob_usage_reqs(
-                toString(accessTagValue(TAG_BLOB_USAGE_REQUIREMENTS, opParam)));
-            break;
-        case Tag::USER_AUTH_TYPE:
-            operationConfig->set_user_auth_type(
-                toString(accessTagValue(TAG_USER_AUTH_TYPE, opParam)));
-            break;
-        default:
-            break;
-        }
-    }
-}
-
-void checkOpCharacteristics(const hidl_vec<KeyParameter>& characteristics,
-                            OperationConfig* operationConfig) {
-    for (auto& opParam : characteristics) {
-        switch (opParam.tag) {
-        case Tag::BLOCK_MODE:
-            operationConfig->set_block_mode(toString(accessTagValue(TAG_BLOCK_MODE, opParam)));
-            break;
-        case Tag::PADDING:
-            operationConfig->set_padding(toString(accessTagValue(TAG_PADDING, opParam)));
-            break;
-        case Tag::DIGEST:
-            operationConfig->set_digest(toString(accessTagValue(TAG_DIGEST, opParam)));
-            break;
-        default:
-            break;
-        }
-    }
-}
-
-void OperationProtoHandler::uploadOpAsProto(Operation& op, bool wasOpSuccessful) {
-    std::lock_guard<std::mutex> lock(op_upload_mutex);
-    OperationConfig operationConfig;
-    determinePurpose(op.purpose, &operationConfig);
-    checkKeyCharacteristics(op.characteristics.softwareEnforced, &operationConfig);
-    checkKeyCharacteristics(op.characteristics.hardwareEnforced, &operationConfig);
-    checkOpCharacteristics(op.params, &operationConfig);
-    operationConfig.set_was_op_successful(wasOpSuccessful);
-    // Only bother with counting an hour out when an operation entry is actually
-    // added
-    if (protoMap.empty()) {
-        start_time = std::chrono::steady_clock::now();
-    }
-    auto cur_time = std::chrono::steady_clock::now();
-
-    // Add operations to a map within the time duration of an hour. Deduplicate
-    // repeated ops by incrementing the counter of the original one stored and
-    // discarding the new one.
-    protoMap[operationConfig.SerializeAsString()]++;
-
-    if (cur_time - start_time >= kCollectionTime) {
-        // Iterate through the unordered map and dump all the operation protos
-        // accumulated over the hour into the holding list proto after setting
-        // their counts.
-        OperationConfigEvents opConfigEvents;
-        for (auto elem : protoMap) {
-            OperationConfigEvent* event = opConfigEvents.add_op_config_events();
-            event->mutable_op_config()->ParseFromString(elem.first);
-            event->set_count(elem.second);
-        }
-        android::sp<android::os::DropBoxManager> dropbox(new android::os::DropBoxManager);
-        size_t size = opConfigEvents.ByteSize();
-        auto data = std::make_unique<uint8_t[]>(size);
-        opConfigEvents.SerializeWithCachedSizesToArray(data.get());
-        dropbox->addData(android::String16("keymaster"), data.get(), size, 0);
-        protoMap.clear();
-    }
-}
-
-}  // namespace keystore
diff --git a/keystore/operation_proto_handler.h b/keystore/operation_proto_handler.h
deleted file mode 100644
index 64d0a59..0000000
--- a/keystore/operation_proto_handler.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 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_OPERATION_PROTO_HANDLER_H_
-#define KEYSTORE_OPERATION_PROTO_HANDLER_H_
-
-#include "operation_config.pb.h"
-#include "operation_struct.h"
-#include <chrono>
-#include <mutex>
-#include <unordered_map>
-#include <vector>
-
-namespace keystore {
-
-using ::android::IBinder;
-using keymaster::support::Keymaster;
-
-class OperationProtoHandler {
-  public:
-    void uploadOpAsProto(Operation& op, bool wasOpSuccessful);
-
-  private:
-    std::unordered_map<std::string, int> protoMap;
-    std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now();
-    std::mutex op_upload_mutex;
-};
-
-}  // namespace keystore
-
-#endif  // KEYSTORE_OPERATION_PROTO_HANDLER_H_
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index d3805cb..a48396a 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -20,14 +20,18 @@
     rustlibs: [
         "libanyhow",
         "libkeystore_aidl_generated",
+        "libkeystore2_selinux",
+        "liblibsqlite3_sys",
         "liblog_rust",
+        "librand",
+        "librusqlite",
         "libthiserror",
     ],
 }
 
 rust_test {
     name: "keystore2_test",
-    crate_name: "keystore2_test",
+    crate_name: "keystore2",
     srcs: ["src/lib.rs"],
     test_suites: ["general-tests"],
     auto_gen_config: true,
@@ -35,7 +39,10 @@
         "libandroid_logger",
         "libanyhow",
         "libkeystore_aidl_generated",
+        "libkeystore2_selinux",
+        "liblibsqlite3_sys",
         "liblog_rust",
+        "librusqlite",
         "libthiserror",
     ],
 }
diff --git a/keystore2/selinux/Android.bp b/keystore2/selinux/Android.bp
new file mode 100644
index 0000000..acbf5ef
--- /dev/null
+++ b/keystore2/selinux/Android.bp
@@ -0,0 +1,54 @@
+// Copyright 2020, 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.
+
+rust_library {
+    name: "libkeystore2_selinux",
+    crate_name: "keystore2_selinux",
+    srcs: [
+        "src/lib.rs",
+    ],
+
+    shared_libs: [
+        "libselinux",
+    ],
+
+    rustlibs: [
+        "libanyhow",
+        "liblog_rust",
+        "libselinux_bindgen",
+        "libthiserror",
+    ],
+}
+
+rust_test {
+    name: "keystore2_selinux_test",
+    srcs: [
+        "src/lib.rs",
+    ],
+    crate_name: "keystore2_selinux_test",
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
+
+    shared_libs: [
+        "libselinux",
+    ],
+
+    rustlibs: [
+        "libandroid_logger",
+        "libanyhow",
+        "liblog_rust",
+        "libselinux_bindgen",
+        "libthiserror",
+    ],
+}
diff --git a/keystore2/selinux/TEST_MAPPING b/keystore2/selinux/TEST_MAPPING
new file mode 100644
index 0000000..0e68257
--- /dev/null
+++ b/keystore2/selinux/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "keystore2_selinux_test"
+    }
+  ]
+}
diff --git a/keystore2/selinux/src/lib.rs b/keystore2/selinux/src/lib.rs
new file mode 100644
index 0000000..30a235a
--- /dev/null
+++ b/keystore2/selinux/src/lib.rs
@@ -0,0 +1,419 @@
+// Copyright 2020, 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.
+
+// #![allow(missing_docs)]
+
+//! This crate provides some safe wrappers around the libselinux API. It is currently limited
+//! to the API surface that Keystore 2.0 requires to perform permission checks against
+//! the SEPolicy. Notably, it provides wrappers for:
+//!  * getcon
+//!  * selinux_check_access
+//!  * selabel_lookup for the keystore2_key backend.
+//! And it provides an owning wrapper around context strings `Context`.
+
+use std::ffi::{CStr, CString};
+use std::fmt;
+use std::io;
+pub use std::ops::Deref;
+use std::os::raw::c_char;
+use std::ptr;
+use std::sync;
+
+use selinux_bindgen as selinux;
+
+use anyhow::Context as AnyhowContext;
+use anyhow::{anyhow, Result};
+
+use selinux::SELABEL_CTX_ANDROID_KEYSTORE2_KEY;
+use selinux::SELINUX_CB_LOG;
+
+static SELINUX_LOG_INIT: sync::Once = sync::Once::new();
+
+fn redirect_selinux_logs_to_logcat() {
+    // `selinux_set_callback` assigned the static lifetime function pointer
+    // `selinux_log_callback` to a static lifetime variable.
+    let cb = selinux::selinux_callback { func_log: Some(selinux::selinux_log_callback) };
+    unsafe {
+        selinux::selinux_set_callback(SELINUX_CB_LOG as i32, cb);
+    }
+}
+
+// This function must be called before any entrypoint into lib selinux.
+// Or leave a comment reasoning why calling this macro is not necessary
+// for a given entry point.
+fn init_logger_once() {
+    SELINUX_LOG_INIT.call_once(redirect_selinux_logs_to_logcat)
+}
+
+/// Selinux Error code.
+#[derive(thiserror::Error, Debug, PartialEq)]
+pub enum Error {
+    /// Indicates that an access check yielded no access.
+    #[error("Permission Denied")]
+    PermissionDenied,
+    /// Indicates an unexpected system error. Nested string provides some details.
+    #[error("Selinux SystemError: {0}")]
+    SystemError(String),
+}
+
+impl Error {
+    /// Constructs a `PermissionDenied` error.
+    pub fn perm() -> Self {
+        Error::PermissionDenied
+    }
+    fn sys<T: Into<String>>(s: T) -> Self {
+        Error::SystemError(s.into())
+    }
+}
+
+/// Context represents an SELinux context string. It can take ownership of a raw
+/// s-string as allocated by `getcon` or `selabel_lookup`. In this case it uses
+/// `freecon` to free the resources when dropped. In its second variant it stores
+/// an `std::ffi::CString` that can be initialized from a Rust string slice.
+pub enum Context {
+    /// Wraps a raw context c-string as returned by libselinux.
+    Raw(*mut ::std::os::raw::c_char),
+    /// Stores a context string as `std::ffi::CString`.
+    CString(CString),
+}
+
+impl fmt::Display for Context {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", (**self).to_str().unwrap_or("Invalid context"))
+    }
+}
+
+impl Drop for Context {
+    fn drop(&mut self) {
+        if let Self::Raw(p) = self {
+            // No need to initialize the logger here, because
+            // `freecon` cannot run unless `Backend::lookup` or `getcon`
+            // has run.
+            unsafe { selinux::freecon(*p) };
+        }
+    }
+}
+
+impl Deref for Context {
+    type Target = CStr;
+
+    fn deref(&self) -> &Self::Target {
+        match self {
+            Self::Raw(p) => unsafe { CStr::from_ptr(*p) },
+            Self::CString(cstr) => &cstr,
+        }
+    }
+}
+
+impl Context {
+    /// Initializes the `Context::CString` variant from a Rust string slice.
+    pub fn new(con: &str) -> Result<Self> {
+        Ok(Self::CString(
+            CString::new(con)
+                .with_context(|| format!("Failed to create Context with \"{}\"", con))?,
+        ))
+    }
+}
+
+/// The backend trait provides a uniform interface to all libselinux context backends.
+/// Currently, we only implement the KeystoreKeyBackend though.
+pub trait Backend {
+    /// Implementers use libselinux `selabel_lookup` to lookup the context for the given `key`.
+    fn lookup(&self, key: &str) -> Result<Context>;
+}
+
+/// Keystore key backend takes onwnership of the SELinux context handle returned by
+/// `selinux_android_keystore2_key_context_handle` and uses `selabel_close` to free
+/// the handle when dropped.
+/// It implements `Backend` to provide keystore_key label lookup functionality.
+pub struct KeystoreKeyBackend {
+    handle: *mut selinux::selabel_handle,
+}
+
+impl KeystoreKeyBackend {
+    const BACKEND_TYPE: i32 = SELABEL_CTX_ANDROID_KEYSTORE2_KEY as i32;
+
+    /// Creates a new instance representing an SELinux context handle as returned by
+    /// `selinux_android_keystore2_key_context_handle`.
+    pub fn new() -> Result<Self> {
+        init_logger_once();
+        let handle = unsafe { selinux::selinux_android_keystore2_key_context_handle() };
+        if handle.is_null() {
+            return Err(anyhow!(Error::sys("Failed to open KeystoreKeyBackend")));
+        }
+        Ok(KeystoreKeyBackend { handle })
+    }
+}
+
+impl Drop for KeystoreKeyBackend {
+    fn drop(&mut self) {
+        // No need to initialize the logger here because it cannot be called unless
+        // KeystoreKeyBackend::new has run.
+        unsafe { selinux::selabel_close(self.handle) };
+    }
+}
+
+impl Backend for KeystoreKeyBackend {
+    fn lookup(&self, key: &str) -> Result<Context> {
+        let mut con: *mut c_char = ptr::null_mut();
+        let c_key = CString::new(key).with_context(|| {
+            format!("selabel_lookup: Failed to convert key \"{}\" to CString.", key)
+        })?;
+        match unsafe {
+            // No need to initialize the logger here because it cannot run unless
+            // KeystoreKeyBackend::new has run.
+            selinux::selabel_lookup(self.handle, &mut con, c_key.as_ptr(), Self::BACKEND_TYPE)
+        } {
+            0 => {
+                if !con.is_null() {
+                    Ok(Context::Raw(con))
+                } else {
+                    Err(anyhow!(Error::sys(format!(
+                        "selabel_lookup returned a NULL context for key \"{}\"",
+                        key
+                    ))))
+                }
+            }
+            _ => Err(anyhow!(io::Error::last_os_error()))
+                .with_context(|| format!("selabel_lookup failed for key \"{}\"", key)),
+        }
+    }
+}
+
+/// Safe wrapper around libselinux `getcon`. It initializes the `Context::Raw` variant of the
+/// returned `Context`.
+///
+/// ## Return
+///  * Ok(Context::Raw()) if successful.
+///  * Err(Error::sys()) if getcon succeeded but returned a NULL pointer.
+///  * Err(io::Error::last_os_error()) if getcon failed.
+pub fn getcon() -> Result<Context> {
+    init_logger_once();
+    let mut con: *mut c_char = ptr::null_mut();
+    match unsafe { selinux::getcon(&mut con) } {
+        0 => {
+            if !con.is_null() {
+                Ok(Context::Raw(con))
+            } else {
+                Err(anyhow!(Error::sys("getcon returned a NULL context")))
+            }
+        }
+        _ => Err(anyhow!(io::Error::last_os_error())).context("getcon failed"),
+    }
+}
+
+/// Safe wrapper around selinux_check_access.
+///
+/// ## Return
+///  * Ok(()) iff the requested access was granted.
+///  * Err(anyhow!(Error::perm()))) if the permission was denied.
+///  * Err(anyhow!(ioError::last_os_error())) if any other error occurred while performing
+///            the access check.
+pub fn check_access(source: &Context, target: &Context, tclass: &str, perm: &str) -> Result<()> {
+    init_logger_once();
+    let c_tclass = CString::new(tclass).with_context(|| {
+        format!("check_access: Failed to convert tclass \"{}\" to CString.", tclass)
+    })?;
+    let c_perm = CString::new(perm).with_context(|| {
+        format!("check_access: Failed to convert perm \"{}\" to CString.", perm)
+    })?;
+
+    match unsafe {
+        selinux::selinux_check_access(
+            source.as_ptr(),
+            target.as_ptr(),
+            c_tclass.as_ptr(),
+            c_perm.as_ptr(),
+            ptr::null_mut(),
+        )
+    } {
+        0 => Ok(()),
+        _ => {
+            let e = io::Error::last_os_error();
+            match e.kind() {
+                io::ErrorKind::PermissionDenied => Err(anyhow!(Error::perm())),
+                _ => Err(anyhow!(e)),
+            }
+            .with_context(|| {
+                format!(
+                    concat!(
+                        "check_access: Failed with sctx: {} tctx: {}",
+                        " with target class: \"{}\" perm: \"{}\""
+                    ),
+                    source, target, tclass, perm
+                )
+            })
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use anyhow::Result;
+
+    /// The su_key namespace as defined in su.te and keystore_key_contexts of the
+    /// SePolicy (system/sepolicy).
+    static SU_KEY_NAMESPACE: &str = "0";
+    /// The shell_key namespace as defined in shell.te and keystore_key_contexts of the
+    /// SePolicy (system/sepolicy).
+    static SHELL_KEY_NAMESPACE: &str = "1";
+
+    fn check_context() -> Result<(Context, &'static str, bool)> {
+        let context = getcon()?;
+        match context.to_str().unwrap() {
+            "u:r:su:s0" => Ok((context, SU_KEY_NAMESPACE, true)),
+            "u:r:shell:s0" => Ok((context, SHELL_KEY_NAMESPACE, false)),
+            c => Err(anyhow!(format!(
+                "This test must be run as \"su\" or \"shell\". Current context: \"{}\"",
+                c
+            ))),
+        }
+    }
+
+    #[test]
+    fn test_getcon() -> Result<()> {
+        check_context()?;
+        Ok(())
+    }
+
+    #[test]
+    fn test_label_lookup() -> Result<()> {
+        let (_context, namespace, is_su) = check_context()?;
+        let backend = crate::KeystoreKeyBackend::new()?;
+        let context = backend.lookup(namespace)?;
+        if is_su {
+            assert_eq!(context.to_str(), Ok("u:object_r:su_key:s0"));
+        } else {
+            assert_eq!(context.to_str(), Ok("u:object_r:shell_key:s0"));
+        }
+        Ok(())
+    }
+
+    #[test]
+    fn context_from_string() -> Result<()> {
+        let tctx = Context::new("u:object_r:keystore:s0").unwrap();
+        let sctx = Context::new("u:r:system_server:s0").unwrap();
+        check_access(&sctx, &tctx, "keystore2_key", "use")?;
+        Ok(())
+    }
+
+    mod perm {
+        use super::super::*;
+        use super::*;
+        use anyhow::Result;
+
+        /// check_key_perm(perm, privileged, priv_domain)
+        /// `perm` is a permission of the keystore2_key class and `privileged` is a boolean
+        /// indicating whether the permission is considered privileged.
+        /// Privileged permissions are expeced to be denied to `shell` users but granted
+        /// to the given priv_domain.
+        macro_rules! check_key_perm {
+            // "use" is a keyword and cannot be used as an identifier, but we must keep
+            // the permission string intact. So we map the identifier name on use_ while using
+            // the permission string "use". In all other cases we can simply use the stringified
+            // identifier as permission string.
+            (use, $privileged:expr) => {
+                check_key_perm!(use_, $privileged, "use");
+            };
+            ($perm:ident, $privileged:expr) => {
+                check_key_perm!($perm, $privileged, stringify!($perm));
+            };
+            ($perm:ident, $privileged:expr, $p_str:expr) => {
+                #[test]
+                fn $perm() -> Result<()> {
+                    android_logger::init_once(
+                        android_logger::Config::default()
+                            .with_tag("keystore_selinux_tests")
+                            .with_min_level(log::Level::Debug),
+                    );
+                    let scontext = Context::new("u:r:shell:s0")?;
+                    let backend = KeystoreKeyBackend::new()?;
+                    let tcontext = backend.lookup(SHELL_KEY_NAMESPACE)?;
+
+                    if $privileged {
+                        assert_eq!(
+                            Some(&Error::perm()),
+                            check_access(
+                                &scontext,
+                                &tcontext,
+                                "keystore2_key",
+                                $p_str
+                            )
+                            .err()
+                            .unwrap()
+                            .root_cause()
+                            .downcast_ref::<Error>()
+                        );
+                    } else {
+                        assert!(check_access(
+                            &scontext,
+                            &tcontext,
+                            "keystore2_key",
+                            $p_str
+                        )
+                        .is_ok());
+                    }
+                    Ok(())
+                }
+            };
+        }
+
+        check_key_perm!(manage_blob, true);
+        check_key_perm!(delete, false);
+        check_key_perm!(use_dev_id, true);
+        check_key_perm!(req_forced_op, true);
+        check_key_perm!(gen_unique_id, true);
+        check_key_perm!(grant, true);
+        check_key_perm!(get_info, false);
+        check_key_perm!(list, false);
+        check_key_perm!(rebind, false);
+        check_key_perm!(update, false);
+        check_key_perm!(use, false);
+
+        macro_rules! check_keystore_perm {
+            ($perm:ident) => {
+                #[test]
+                fn $perm() -> Result<()> {
+                    let ks_context = Context::new("u:object_r:keystore:s0")?;
+                    let priv_context = Context::new("u:r:system_server:s0")?;
+                    let unpriv_context = Context::new("u:r:shell:s0")?;
+                    assert!(check_access(
+                        &priv_context,
+                        &ks_context,
+                        "keystore2",
+                        stringify!($perm)
+                    )
+                    .is_ok());
+                    assert_eq!(
+                        Some(&Error::perm()),
+                        check_access(&unpriv_context, &ks_context, "keystore2", stringify!($perm))
+                            .err()
+                            .unwrap()
+                            .root_cause()
+                            .downcast_ref::<Error>()
+                    );
+                    Ok(())
+                }
+            };
+        }
+
+        check_keystore_perm!(add_auth);
+        check_keystore_perm!(clear_ns);
+        check_keystore_perm!(get_state);
+        check_keystore_perm!(lock);
+        check_keystore_perm!(reset);
+        check_keystore_perm!(unlock);
+    }
+}
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
new file mode 100644
index 0000000..394b7be
--- /dev/null
+++ b/keystore2/src/database.rs
@@ -0,0 +1,397 @@
+// Copyright 2020, 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.
+
+// TODO: Once this is stable, remove this and document everything public.
+#![allow(missing_docs)]
+
+use crate::error::Error as KsError;
+use anyhow::{Context, Result};
+use keystore_aidl_generated as aidl;
+#[cfg(not(test))]
+use rand::prelude::random;
+use rusqlite::{params, Connection, TransactionBehavior, NO_PARAMS};
+#[cfg(test)]
+use tests::random;
+
+pub struct KeystoreDB {
+    conn: Connection,
+}
+
+impl KeystoreDB {
+    // TODO(b/160882985): Figure out the location for this file.
+    #[cfg(not(test))]
+    pub fn new() -> Result<KeystoreDB> {
+        KeystoreDB::new_with_filename("persistent.sql")
+    }
+
+    #[cfg(test)]
+    pub fn new() -> Result<KeystoreDB> {
+        KeystoreDB::new_with_filename("")
+    }
+
+    fn new_with_filename(persistent_file: &str) -> Result<KeystoreDB> {
+        let db = KeystoreDB {
+            conn: Connection::open_in_memory()
+                .context("Failed to initialize sqlite connection.")?,
+        };
+        db.attach_databases(persistent_file).context("Failed to create KeystoreDB.")?;
+        db.init_tables().context("Failed to create KeystoreDB.")?;
+        Ok(db)
+    }
+
+    fn attach_databases(&self, persistent_file: &str) -> Result<()> {
+        self.conn
+            .execute("ATTACH DATABASE ? as 'persistent';", params![persistent_file])
+            .context("Failed to attach databases.")?;
+        Ok(())
+    }
+
+    fn init_tables(&self) -> Result<()> {
+        self.conn
+            .execute(
+                "CREATE TABLE IF NOT EXISTS persistent.keyentry (
+                     id INTEGER UNIQUE,
+                     creation_date DATETIME,
+                     domain INTEGER,
+                     namespace INTEGER,
+                     alias TEXT);",
+                NO_PARAMS,
+            )
+            .context("Failed to initialize \"keyentry\" table.")?;
+        Ok(())
+    }
+
+    pub fn create_key_entry(&self, domain: aidl::Domain, namespace: i64) -> Result<i64> {
+        match domain {
+            aidl::Domain::App | aidl::Domain::SELinux => {}
+            _ => {
+                return Err(KsError::sys())
+                    .context(format!("Domain {:?} must be either App or SELinux.", domain));
+            }
+        }
+        // Loop until we get a unique id.
+        loop {
+            let newid: i64 = random();
+            let ret = self.conn.execute(
+                "INSERT into persistent.keyentry (id, creation_date, domain, namespace, alias)
+                     VALUES(?, datetime('now'), ?, ?, NULL);",
+                params![newid, domain as i64, namespace],
+            );
+            match ret {
+                // If the id already existed, try again.
+                Err(rusqlite::Error::SqliteFailure(
+                    libsqlite3_sys::Error {
+                        code: libsqlite3_sys::ErrorCode::ConstraintViolation,
+                        extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
+                    },
+                    _,
+                )) => (),
+                _ => return Ok(newid),
+            }
+        }
+    }
+
+    pub fn rebind_alias(
+        &mut self,
+        newid: u32,
+        alias: &str,
+        domain: aidl::Domain,
+        namespace: i64,
+    ) -> Result<()> {
+        match domain {
+            aidl::Domain::App | aidl::Domain::SELinux => {}
+            _ => {
+                return Err(KsError::sys())
+                    .context(format!("Domain {:?} must be either App or SELinux.", domain));
+            }
+        }
+        let tx = self
+            .conn
+            .transaction_with_behavior(TransactionBehavior::Immediate)
+            .context("Failed to initialize transaction.")?;
+        tx.execute(
+            "UPDATE persistent.keyentry
+                 SET alias = NULL, domain = NULL, namespace = NULL
+                 WHERE alias = ? AND domain = ? AND namespace = ?;",
+            params![alias, domain as i64, namespace],
+        )
+        .context("Failed to rebind existing entry.")?;
+        let result = tx
+            .execute(
+                "UPDATE persistent.keyentry
+                 SET alias = ?
+                 WHERE id = ? AND domain = ? AND namespace = ?;",
+                params![alias, newid, domain as i64, namespace],
+            )
+            .context("Failed to set alias.")?;
+        if result != 1 {
+            // Note that this explicit rollback is not required, as
+            // the transaction should rollback if we do not commit it.
+            // We leave it here for readability.
+            tx.rollback().context("Failed to rollback a failed transaction.")?;
+            return Err(KsError::sys()).context(format!(
+                "Expected to update a single entry but instead updated {}.",
+                result
+            ));
+        }
+        tx.commit().context("Failed to commit transaction.")
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+    use std::cell::RefCell;
+
+    // Ensure that we're using the "injected" random function, not the real one.
+    #[test]
+    fn test_mocked_random() {
+        let rand1 = random();
+        let rand2 = random();
+        let rand3 = random();
+        if rand1 == rand2 {
+            assert_eq!(rand2 + 1, rand3);
+        } else {
+            assert_eq!(rand1 + 1, rand2);
+            assert_eq!(rand2, rand3);
+        }
+    }
+
+    // Ensure we can initialize the database.
+    #[test]
+    fn test_new() -> Result<()> {
+        KeystoreDB::new()?;
+        Ok(())
+    }
+
+    // Test that we have the correct tables.
+    #[test]
+    fn test_tables() -> Result<()> {
+        let db = KeystoreDB::new()?;
+        let tables = db
+            .conn
+            .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
+            .query_map(params![], |row| row.get(0))?
+            .collect::<rusqlite::Result<Vec<String>>>()?;
+        assert_eq!(tables.len(), 1);
+        assert_eq!(tables[0], "keyentry");
+        Ok(())
+    }
+
+    #[test]
+    fn test_no_persistence_for_tests() -> Result<()> {
+        let db = KeystoreDB::new()?;
+
+        db.create_key_entry(aidl::Domain::App, 100)?;
+        let entries = get_keyentry(&db)?;
+        assert_eq!(entries.len(), 1);
+        let db = KeystoreDB::new()?;
+
+        let entries = get_keyentry(&db)?;
+        assert_eq!(entries.len(), 0);
+        Ok(())
+    }
+
+    #[test]
+    fn test_persistence_for_files() -> Result<()> {
+        let persistent = TempFile { filename: "/data/local/tmp/persistent.sql" };
+        let db = KeystoreDB::new_with_filename(persistent.filename)?;
+
+        db.create_key_entry(aidl::Domain::App, 100)?;
+        let entries = get_keyentry(&db)?;
+        assert_eq!(entries.len(), 1);
+        let db = KeystoreDB::new_with_filename(persistent.filename)?;
+
+        let entries_new = get_keyentry(&db)?;
+        assert_eq!(entries, entries_new);
+        Ok(())
+    }
+
+    #[test]
+    fn test_create_key_entry() -> Result<()> {
+        use aidl::Domain;
+
+        fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>) {
+            (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref())
+        }
+
+        let db = KeystoreDB::new()?;
+
+        db.create_key_entry(Domain::App, 100)?;
+        db.create_key_entry(Domain::SELinux, 101)?;
+
+        let entries = get_keyentry(&db)?;
+        assert_eq!(entries.len(), 2);
+        assert_eq!(extractor(&entries[0]), (Domain::App, 100, None));
+        assert_eq!(extractor(&entries[1]), (Domain::SELinux, 101, None));
+
+        // Test that we must pass in a valid Domain.
+        check_result_is_error_containing_string(
+            db.create_key_entry(Domain::Grant, 102),
+            "Domain Grant must be either App or SELinux.",
+        );
+        check_result_is_error_containing_string(
+            db.create_key_entry(Domain::Blob, 103),
+            "Domain Blob must be either App or SELinux.",
+        );
+        check_result_is_error_containing_string(
+            db.create_key_entry(Domain::KeyId, 104),
+            "Domain KeyId must be either App or SELinux.",
+        );
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_rebind_alias() -> Result<()> {
+        use aidl::Domain;
+
+        fn extractor(ke: &KeyEntryRow) -> (Option<Domain>, Option<i64>, Option<&str>) {
+            (ke.domain, ke.namespace, ke.alias.as_deref())
+        }
+
+        let mut db = KeystoreDB::new()?;
+        db.create_key_entry(Domain::App, 42)?;
+        db.create_key_entry(Domain::App, 42)?;
+        let entries = get_keyentry(&db)?;
+        assert_eq!(entries.len(), 2);
+        assert_eq!(extractor(&entries[0]), (Some(Domain::App), Some(42), None));
+        assert_eq!(extractor(&entries[1]), (Some(Domain::App), Some(42), None));
+
+        // Test that the first call to rebind_alias sets the alias.
+        db.rebind_alias(entries[0].id, "foo", Domain::App, 42)?;
+        let entries = get_keyentry(&db)?;
+        assert_eq!(entries.len(), 2);
+        assert_eq!(extractor(&entries[0]), (Some(Domain::App), Some(42), Some("foo")));
+        assert_eq!(extractor(&entries[1]), (Some(Domain::App), Some(42), None));
+
+        // Test that the second call to rebind_alias also empties the old one.
+        db.rebind_alias(entries[1].id, "foo", Domain::App, 42)?;
+        let entries = get_keyentry(&db)?;
+        assert_eq!(entries.len(), 2);
+        assert_eq!(extractor(&entries[0]), (None, None, None));
+        assert_eq!(extractor(&entries[1]), (Some(Domain::App), Some(42), Some("foo")));
+
+        // Test that we must pass in a valid Domain.
+        check_result_is_error_containing_string(
+            db.rebind_alias(0, "foo", Domain::Grant, 42),
+            "Domain Grant must be either App or SELinux.",
+        );
+        check_result_is_error_containing_string(
+            db.rebind_alias(0, "foo", Domain::Blob, 42),
+            "Domain Blob must be either App or SELinux.",
+        );
+        check_result_is_error_containing_string(
+            db.rebind_alias(0, "foo", Domain::KeyId, 42),
+            "Domain KeyId must be either App or SELinux.",
+        );
+
+        // Test that we correctly handle setting an alias for something that does not exist.
+        check_result_is_error_containing_string(
+            db.rebind_alias(0, "foo", Domain::SELinux, 42),
+            "Expected to update a single entry but instead updated 0",
+        );
+        // Test that we correctly abort the transaction in this case.
+        let entries = get_keyentry(&db)?;
+        assert_eq!(entries.len(), 2);
+        assert_eq!(extractor(&entries[0]), (None, None, None));
+        assert_eq!(extractor(&entries[1]), (Some(Domain::App), Some(42), Some("foo")));
+
+        Ok(())
+    }
+
+    // Helpers
+
+    // Checks that the given result is an error containing the given string.
+    fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
+        let error_str = format!(
+            "{:#?}",
+            result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
+        );
+        assert!(
+            error_str.contains(target),
+            "The string \"{}\" should contain \"{}\"",
+            error_str,
+            target
+        );
+    }
+
+    #[derive(Debug, PartialEq)]
+    #[allow(dead_code)]
+    struct KeyEntryRow {
+        id: u32,
+        creation_date: String,
+        domain: Option<aidl::Domain>,
+        namespace: Option<i64>,
+        alias: Option<String>,
+    }
+
+    fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
+        db.conn
+            .prepare("SELECT * FROM persistent.keyentry;")?
+            .query_map(NO_PARAMS, |row| {
+                let domain: Option<i32> = row.get(2)?;
+                Ok(KeyEntryRow {
+                    id: row.get(0)?,
+                    creation_date: row.get(1)?,
+                    domain: domain.map(domain_from_integer),
+                    namespace: row.get(3)?,
+                    alias: row.get(4)?,
+                })
+            })?
+            .map(|r| r.context("Could not read keyentry row."))
+            .collect::<Result<Vec<_>>>()
+    }
+
+    // TODO: Replace this with num_derive.
+    fn domain_from_integer(value: i32) -> aidl::Domain {
+        use aidl::Domain;
+        match value {
+            x if Domain::App as i32 == x => Domain::App,
+            x if Domain::Grant as i32 == x => Domain::Grant,
+            x if Domain::SELinux as i32 == x => Domain::SELinux,
+            x if Domain::Blob as i32 == x => Domain::Blob,
+            x if Domain::KeyId as i32 == x => Domain::KeyId,
+            _ => panic!("Unexpected domain: {}", value),
+        }
+    }
+
+    // A class that deletes a file when it is dropped.
+    // TODO: If we ever add a crate that does this, we can use it instead.
+    struct TempFile {
+        filename: &'static str,
+    }
+
+    impl Drop for TempFile {
+        fn drop(&mut self) {
+            std::fs::remove_file(self.filename).expect("Cannot delete temporary file");
+        }
+    }
+
+    // Use a custom random number generator that repeats each number once.
+    // This allows us to test repeated elements.
+
+    thread_local! {
+        static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
+    }
+
+    pub fn random() -> i64 {
+        RANDOM_COUNTER.with(|counter| {
+            let result = *counter.borrow() / 2;
+            *counter.borrow_mut() += 1;
+            result
+        })
+    }
+}
diff --git a/keystore2/src/error.rs b/keystore2/src/error.rs
index e58d3ce..e6443b7 100644
--- a/keystore2/src/error.rs
+++ b/keystore2/src/error.rs
@@ -36,6 +36,8 @@
 use keystore_aidl_generated as aidl;
 use keystore_aidl_generated::ResponseCode as AidlRc;
 
+use keystore2_selinux as selinux;
+
 pub use aidl::ResponseCode;
 
 /// AidlResult wraps the `android.security.keystore2.Result` generated from AIDL
@@ -89,7 +91,10 @@
         match root_cause.downcast_ref::<Error>() {
             Some(Error::Rc(rcode)) => AidlResult::rc(*rcode),
             Some(Error::Km(ec)) => AidlResult::ec(*ec),
-            None => AidlResult::rc(AidlRc::SystemError),
+            None => match root_cause.downcast_ref::<selinux::Error>() {
+                Some(selinux::Error::PermissionDenied) => AidlResult::rc(AidlRc::PermissionDenied),
+                _ => AidlResult::rc(AidlRc::SystemError),
+            },
         }
     }
 }
@@ -101,6 +106,7 @@
 /// All `Error::Rc(x)` variants get mapped onto `aidl::Result{x, 0}`.
 /// All `Error::Km(x)` variants get mapped onto
 /// `aidl::Result{aidl::ResponseCode::KeymintErrorCode, x}`.
+/// `selinux::Error::perm()` is mapped on `aidl::Result{aidl::ResponseCode::PermissionDenied, 0}`.
 ///
 /// All non `Error` error conditions get mapped onto
 /// `aidl::Result{aidl::ResponseCode::SystemError}`.
@@ -168,6 +174,14 @@
         nested_nested_ok(rc).context("nested ok")
     }
 
+    fn nested_nested_selinux_perm() -> anyhow::Result<()> {
+        Err(anyhow!(selinux::Error::perm())).context("nested nexted selinux permission denied")
+    }
+
+    fn nested_selinux_perm() -> anyhow::Result<()> {
+        nested_nested_selinux_perm().context("nested selinux permission denied")
+    }
+
     #[derive(Debug, thiserror::Error)]
     enum TestError {
         #[error("TestError::Fail")]
@@ -263,6 +277,11 @@
         );
         assert_eq!(AidlResult::ok(), map_or_log_err(nested_ok(AidlRc::Ok), AidlResult::rc));
 
+        // selinux::Error::Perm() needs to be mapped to AidlRc::PermissionDenied
+        assert_eq!(
+            AidlResult::rc(AidlRc::PermissionDenied),
+            map_or_log_err(nested_selinux_perm(), |_| AidlResult::ec(0))
+        );
         Ok(())
     }
 } // mod tests
diff --git a/keystore2/src/lib.rs b/keystore2/src/lib.rs
index d2c55a7..dfdd228 100644
--- a/keystore2/src/lib.rs
+++ b/keystore2/src/lib.rs
@@ -14,4 +14,5 @@
 
 //! This crate implements the Android Keystore 2.0 service.
 
+pub mod database;
 pub mod error;