Move large test modules into separate files

This complies better with the Android Rust style guide, and makes it
easier to navigate the code.

Test: keystore2_test  libwatchdog_rs.test  librkpd_client.test
Change-Id: Iceb49e309af66ec16d31da66b328936b0312061a
diff --git a/keystore2/src/async_task.rs b/keystore2/src/async_task.rs
index 6548445..16401a4 100644
--- a/keystore2/src/async_task.rs
+++ b/keystore2/src/async_task.rs
@@ -27,6 +27,9 @@
     thread,
 };
 
+#[cfg(test)]
+mod tests;
+
 #[derive(Debug, PartialEq, Eq)]
 enum State {
     Exiting,
@@ -256,279 +259,3 @@
         state.state = State::Running;
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use super::{AsyncTask, Shelf};
-    use std::sync::{
-        mpsc::{channel, sync_channel, RecvTimeoutError},
-        Arc,
-    };
-    use std::time::Duration;
-
-    #[test]
-    fn test_shelf() {
-        let mut shelf = Shelf::default();
-
-        let s = "A string".to_string();
-        assert_eq!(shelf.put(s), None);
-
-        let s2 = "Another string".to_string();
-        assert_eq!(shelf.put(s2), Some("A string".to_string()));
-
-        // Put something of a different type on the shelf.
-        #[derive(Debug, PartialEq, Eq)]
-        struct Elf {
-            pub name: String,
-        }
-        let e1 = Elf { name: "Glorfindel".to_string() };
-        assert_eq!(shelf.put(e1), None);
-
-        // The String value is still on the shelf.
-        let s3 = shelf.get_downcast_ref::<String>().unwrap();
-        assert_eq!(s3, "Another string");
-
-        // As is the Elf.
-        {
-            let e2 = shelf.get_downcast_mut::<Elf>().unwrap();
-            assert_eq!(e2.name, "Glorfindel");
-            e2.name = "Celeborn".to_string();
-        }
-
-        // Take the Elf off the shelf.
-        let e3 = shelf.remove_downcast_ref::<Elf>().unwrap();
-        assert_eq!(e3.name, "Celeborn");
-
-        assert_eq!(shelf.remove_downcast_ref::<Elf>(), None);
-
-        // No u64 value has been put on the shelf, so getting one gives the default value.
-        {
-            let i = shelf.get_mut::<u64>();
-            assert_eq!(*i, 0);
-            *i = 42;
-        }
-        let i2 = shelf.get_downcast_ref::<u64>().unwrap();
-        assert_eq!(*i2, 42);
-
-        // No i32 value has ever been seen near the shelf.
-        assert_eq!(shelf.get_downcast_ref::<i32>(), None);
-        assert_eq!(shelf.get_downcast_mut::<i32>(), None);
-        assert_eq!(shelf.remove_downcast_ref::<i32>(), None);
-    }
-
-    #[test]
-    fn test_async_task() {
-        let at = AsyncTask::default();
-
-        // First queue up a job that blocks until we release it, to avoid
-        // unpredictable synchronization.
-        let (start_sender, start_receiver) = channel();
-        at.queue_hi(move |shelf| {
-            start_receiver.recv().unwrap();
-            // Put a trace vector on the shelf
-            shelf.put(Vec::<String>::new());
-        });
-
-        // Queue up some high-priority and low-priority jobs.
-        for i in 0..3 {
-            let j = i;
-            at.queue_lo(move |shelf| {
-                let trace = shelf.get_mut::<Vec<String>>();
-                trace.push(format!("L{}", j));
-            });
-            let j = i;
-            at.queue_hi(move |shelf| {
-                let trace = shelf.get_mut::<Vec<String>>();
-                trace.push(format!("H{}", j));
-            });
-        }
-
-        // Finally queue up a low priority job that emits the trace.
-        let (trace_sender, trace_receiver) = channel();
-        at.queue_lo(move |shelf| {
-            let trace = shelf.get_downcast_ref::<Vec<String>>().unwrap();
-            trace_sender.send(trace.clone()).unwrap();
-        });
-
-        // Ready, set, go.
-        start_sender.send(()).unwrap();
-        let trace = trace_receiver.recv().unwrap();
-
-        assert_eq!(trace, vec!["H0", "H1", "H2", "L0", "L1", "L2"]);
-    }
-
-    #[test]
-    fn test_async_task_chain() {
-        let at = Arc::new(AsyncTask::default());
-        let (sender, receiver) = channel();
-        // Queue up a job that will queue up another job. This confirms
-        // that the job is not invoked with any internal AsyncTask locks held.
-        let at_clone = at.clone();
-        at.queue_hi(move |_shelf| {
-            at_clone.queue_lo(move |_shelf| {
-                sender.send(()).unwrap();
-            });
-        });
-        receiver.recv().unwrap();
-    }
-
-    #[test]
-    #[should_panic]
-    fn test_async_task_panic() {
-        let at = AsyncTask::default();
-        at.queue_hi(|_shelf| {
-            panic!("Panic from queued job");
-        });
-        // Queue another job afterwards to ensure that the async thread gets joined.
-        let (done_sender, done_receiver) = channel();
-        at.queue_hi(move |_shelf| {
-            done_sender.send(()).unwrap();
-        });
-        done_receiver.recv().unwrap();
-    }
-
-    #[test]
-    fn test_async_task_idle() {
-        let at = AsyncTask::new(Duration::from_secs(3));
-        // Need a SyncSender as it is Send+Sync.
-        let (idle_done_sender, idle_done_receiver) = sync_channel::<()>(3);
-        at.add_idle(move |_shelf| {
-            idle_done_sender.send(()).unwrap();
-        });
-
-        // Queue up some high-priority and low-priority jobs that take time.
-        for _i in 0..3 {
-            at.queue_lo(|_shelf| {
-                std::thread::sleep(Duration::from_millis(500));
-            });
-            at.queue_hi(|_shelf| {
-                std::thread::sleep(Duration::from_millis(500));
-            });
-        }
-        // Final low-priority job.
-        let (done_sender, done_receiver) = channel();
-        at.queue_lo(move |_shelf| {
-            done_sender.send(()).unwrap();
-        });
-
-        // Nothing happens until the last job completes.
-        assert_eq!(
-            idle_done_receiver.recv_timeout(Duration::from_secs(1)),
-            Err(RecvTimeoutError::Timeout)
-        );
-        done_receiver.recv().unwrap();
-        // Now that the last low-priority job has completed, the idle task should
-        // fire pretty much immediately.
-        idle_done_receiver.recv_timeout(Duration::from_millis(50)).unwrap();
-
-        // Idle callback not executed again even if we wait for a while.
-        assert_eq!(
-            idle_done_receiver.recv_timeout(Duration::from_secs(3)),
-            Err(RecvTimeoutError::Timeout)
-        );
-
-        // However, if more work is done then there's another chance to go idle.
-        let (done_sender, done_receiver) = channel();
-        at.queue_hi(move |_shelf| {
-            std::thread::sleep(Duration::from_millis(500));
-            done_sender.send(()).unwrap();
-        });
-        // Idle callback not immediately executed, because the high priority
-        // job is taking a while.
-        assert_eq!(
-            idle_done_receiver.recv_timeout(Duration::from_millis(1)),
-            Err(RecvTimeoutError::Timeout)
-        );
-        done_receiver.recv().unwrap();
-        idle_done_receiver.recv_timeout(Duration::from_millis(50)).unwrap();
-    }
-
-    #[test]
-    fn test_async_task_multiple_idle() {
-        let at = AsyncTask::new(Duration::from_secs(3));
-        let (idle_sender, idle_receiver) = sync_channel::<i32>(5);
-        // Queue a high priority job to start things off
-        at.queue_hi(|_shelf| {
-            std::thread::sleep(Duration::from_millis(500));
-        });
-
-        // Multiple idle callbacks.
-        for i in 0..3 {
-            let idle_sender = idle_sender.clone();
-            at.add_idle(move |_shelf| {
-                idle_sender.send(i).unwrap();
-            });
-        }
-
-        // Nothing happens immediately.
-        assert_eq!(
-            idle_receiver.recv_timeout(Duration::from_millis(1)),
-            Err(RecvTimeoutError::Timeout)
-        );
-        // Wait for a moment and the idle jobs should have run.
-        std::thread::sleep(Duration::from_secs(1));
-
-        let mut results = Vec::new();
-        while let Ok(i) = idle_receiver.recv_timeout(Duration::from_millis(1)) {
-            results.push(i);
-        }
-        assert_eq!(results, [0, 1, 2]);
-    }
-
-    #[test]
-    fn test_async_task_idle_queues_job() {
-        let at = Arc::new(AsyncTask::new(Duration::from_secs(1)));
-        let at_clone = at.clone();
-        let (idle_sender, idle_receiver) = sync_channel::<i32>(100);
-        // Add an idle callback that queues a low-priority job.
-        at.add_idle(move |shelf| {
-            at_clone.queue_lo(|_shelf| {
-                // Slow things down so the channel doesn't fill up.
-                std::thread::sleep(Duration::from_millis(50));
-            });
-            let i = shelf.get_mut::<i32>();
-            idle_sender.send(*i).unwrap();
-            *i += 1;
-        });
-
-        // Nothing happens immediately.
-        assert_eq!(
-            idle_receiver.recv_timeout(Duration::from_millis(1500)),
-            Err(RecvTimeoutError::Timeout)
-        );
-
-        // Once we queue a normal job, things start.
-        at.queue_hi(|_shelf| {});
-        assert_eq!(0, idle_receiver.recv_timeout(Duration::from_millis(200)).unwrap());
-
-        // The idle callback queues a job, and completion of that job
-        // means the task is going idle again...so the idle callback will
-        // be called repeatedly.
-        assert_eq!(1, idle_receiver.recv_timeout(Duration::from_millis(100)).unwrap());
-        assert_eq!(2, idle_receiver.recv_timeout(Duration::from_millis(100)).unwrap());
-        assert_eq!(3, idle_receiver.recv_timeout(Duration::from_millis(100)).unwrap());
-    }
-
-    #[test]
-    #[should_panic]
-    fn test_async_task_idle_panic() {
-        let at = AsyncTask::new(Duration::from_secs(1));
-        let (idle_sender, idle_receiver) = sync_channel::<()>(3);
-        // Add an idle callback that panics.
-        at.add_idle(move |_shelf| {
-            idle_sender.send(()).unwrap();
-            panic!("Panic from idle callback");
-        });
-        // Queue a job to trigger idleness and ensuing panic.
-        at.queue_hi(|_shelf| {});
-        idle_receiver.recv().unwrap();
-
-        // Queue another job afterwards to ensure that the async thread gets joined
-        // and the panic detected.
-        let (done_sender, done_receiver) = channel();
-        at.queue_hi(move |_shelf| {
-            done_sender.send(()).unwrap();
-        });
-        done_receiver.recv().unwrap();
-    }
-}
diff --git a/keystore2/src/async_task/tests.rs b/keystore2/src/async_task/tests.rs
new file mode 100644
index 0000000..e67303e
--- /dev/null
+++ b/keystore2/src/async_task/tests.rs
@@ -0,0 +1,287 @@
+// 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.
+
+//! Async task tests.
+use super::{AsyncTask, Shelf};
+use std::sync::{
+    mpsc::{channel, sync_channel, RecvTimeoutError},
+    Arc,
+};
+use std::time::Duration;
+
+#[test]
+fn test_shelf() {
+    let mut shelf = Shelf::default();
+
+    let s = "A string".to_string();
+    assert_eq!(shelf.put(s), None);
+
+    let s2 = "Another string".to_string();
+    assert_eq!(shelf.put(s2), Some("A string".to_string()));
+
+    // Put something of a different type on the shelf.
+    #[derive(Debug, PartialEq, Eq)]
+    struct Elf {
+        pub name: String,
+    }
+    let e1 = Elf { name: "Glorfindel".to_string() };
+    assert_eq!(shelf.put(e1), None);
+
+    // The String value is still on the shelf.
+    let s3 = shelf.get_downcast_ref::<String>().unwrap();
+    assert_eq!(s3, "Another string");
+
+    // As is the Elf.
+    {
+        let e2 = shelf.get_downcast_mut::<Elf>().unwrap();
+        assert_eq!(e2.name, "Glorfindel");
+        e2.name = "Celeborn".to_string();
+    }
+
+    // Take the Elf off the shelf.
+    let e3 = shelf.remove_downcast_ref::<Elf>().unwrap();
+    assert_eq!(e3.name, "Celeborn");
+
+    assert_eq!(shelf.remove_downcast_ref::<Elf>(), None);
+
+    // No u64 value has been put on the shelf, so getting one gives the default value.
+    {
+        let i = shelf.get_mut::<u64>();
+        assert_eq!(*i, 0);
+        *i = 42;
+    }
+    let i2 = shelf.get_downcast_ref::<u64>().unwrap();
+    assert_eq!(*i2, 42);
+
+    // No i32 value has ever been seen near the shelf.
+    assert_eq!(shelf.get_downcast_ref::<i32>(), None);
+    assert_eq!(shelf.get_downcast_mut::<i32>(), None);
+    assert_eq!(shelf.remove_downcast_ref::<i32>(), None);
+}
+
+#[test]
+fn test_async_task() {
+    let at = AsyncTask::default();
+
+    // First queue up a job that blocks until we release it, to avoid
+    // unpredictable synchronization.
+    let (start_sender, start_receiver) = channel();
+    at.queue_hi(move |shelf| {
+        start_receiver.recv().unwrap();
+        // Put a trace vector on the shelf
+        shelf.put(Vec::<String>::new());
+    });
+
+    // Queue up some high-priority and low-priority jobs.
+    for i in 0..3 {
+        let j = i;
+        at.queue_lo(move |shelf| {
+            let trace = shelf.get_mut::<Vec<String>>();
+            trace.push(format!("L{}", j));
+        });
+        let j = i;
+        at.queue_hi(move |shelf| {
+            let trace = shelf.get_mut::<Vec<String>>();
+            trace.push(format!("H{}", j));
+        });
+    }
+
+    // Finally queue up a low priority job that emits the trace.
+    let (trace_sender, trace_receiver) = channel();
+    at.queue_lo(move |shelf| {
+        let trace = shelf.get_downcast_ref::<Vec<String>>().unwrap();
+        trace_sender.send(trace.clone()).unwrap();
+    });
+
+    // Ready, set, go.
+    start_sender.send(()).unwrap();
+    let trace = trace_receiver.recv().unwrap();
+
+    assert_eq!(trace, vec!["H0", "H1", "H2", "L0", "L1", "L2"]);
+}
+
+#[test]
+fn test_async_task_chain() {
+    let at = Arc::new(AsyncTask::default());
+    let (sender, receiver) = channel();
+    // Queue up a job that will queue up another job. This confirms
+    // that the job is not invoked with any internal AsyncTask locks held.
+    let at_clone = at.clone();
+    at.queue_hi(move |_shelf| {
+        at_clone.queue_lo(move |_shelf| {
+            sender.send(()).unwrap();
+        });
+    });
+    receiver.recv().unwrap();
+}
+
+#[test]
+#[should_panic]
+fn test_async_task_panic() {
+    let at = AsyncTask::default();
+    at.queue_hi(|_shelf| {
+        panic!("Panic from queued job");
+    });
+    // Queue another job afterwards to ensure that the async thread gets joined.
+    let (done_sender, done_receiver) = channel();
+    at.queue_hi(move |_shelf| {
+        done_sender.send(()).unwrap();
+    });
+    done_receiver.recv().unwrap();
+}
+
+#[test]
+fn test_async_task_idle() {
+    let at = AsyncTask::new(Duration::from_secs(3));
+    // Need a SyncSender as it is Send+Sync.
+    let (idle_done_sender, idle_done_receiver) = sync_channel::<()>(3);
+    at.add_idle(move |_shelf| {
+        idle_done_sender.send(()).unwrap();
+    });
+
+    // Queue up some high-priority and low-priority jobs that take time.
+    for _i in 0..3 {
+        at.queue_lo(|_shelf| {
+            std::thread::sleep(Duration::from_millis(500));
+        });
+        at.queue_hi(|_shelf| {
+            std::thread::sleep(Duration::from_millis(500));
+        });
+    }
+    // Final low-priority job.
+    let (done_sender, done_receiver) = channel();
+    at.queue_lo(move |_shelf| {
+        done_sender.send(()).unwrap();
+    });
+
+    // Nothing happens until the last job completes.
+    assert_eq!(
+        idle_done_receiver.recv_timeout(Duration::from_secs(1)),
+        Err(RecvTimeoutError::Timeout)
+    );
+    done_receiver.recv().unwrap();
+    // Now that the last low-priority job has completed, the idle task should
+    // fire pretty much immediately.
+    idle_done_receiver.recv_timeout(Duration::from_millis(50)).unwrap();
+
+    // Idle callback not executed again even if we wait for a while.
+    assert_eq!(
+        idle_done_receiver.recv_timeout(Duration::from_secs(3)),
+        Err(RecvTimeoutError::Timeout)
+    );
+
+    // However, if more work is done then there's another chance to go idle.
+    let (done_sender, done_receiver) = channel();
+    at.queue_hi(move |_shelf| {
+        std::thread::sleep(Duration::from_millis(500));
+        done_sender.send(()).unwrap();
+    });
+    // Idle callback not immediately executed, because the high priority
+    // job is taking a while.
+    assert_eq!(
+        idle_done_receiver.recv_timeout(Duration::from_millis(1)),
+        Err(RecvTimeoutError::Timeout)
+    );
+    done_receiver.recv().unwrap();
+    idle_done_receiver.recv_timeout(Duration::from_millis(50)).unwrap();
+}
+
+#[test]
+fn test_async_task_multiple_idle() {
+    let at = AsyncTask::new(Duration::from_secs(3));
+    let (idle_sender, idle_receiver) = sync_channel::<i32>(5);
+    // Queue a high priority job to start things off
+    at.queue_hi(|_shelf| {
+        std::thread::sleep(Duration::from_millis(500));
+    });
+
+    // Multiple idle callbacks.
+    for i in 0..3 {
+        let idle_sender = idle_sender.clone();
+        at.add_idle(move |_shelf| {
+            idle_sender.send(i).unwrap();
+        });
+    }
+
+    // Nothing happens immediately.
+    assert_eq!(
+        idle_receiver.recv_timeout(Duration::from_millis(1)),
+        Err(RecvTimeoutError::Timeout)
+    );
+    // Wait for a moment and the idle jobs should have run.
+    std::thread::sleep(Duration::from_secs(1));
+
+    let mut results = Vec::new();
+    while let Ok(i) = idle_receiver.recv_timeout(Duration::from_millis(1)) {
+        results.push(i);
+    }
+    assert_eq!(results, [0, 1, 2]);
+}
+
+#[test]
+fn test_async_task_idle_queues_job() {
+    let at = Arc::new(AsyncTask::new(Duration::from_secs(1)));
+    let at_clone = at.clone();
+    let (idle_sender, idle_receiver) = sync_channel::<i32>(100);
+    // Add an idle callback that queues a low-priority job.
+    at.add_idle(move |shelf| {
+        at_clone.queue_lo(|_shelf| {
+            // Slow things down so the channel doesn't fill up.
+            std::thread::sleep(Duration::from_millis(50));
+        });
+        let i = shelf.get_mut::<i32>();
+        idle_sender.send(*i).unwrap();
+        *i += 1;
+    });
+
+    // Nothing happens immediately.
+    assert_eq!(
+        idle_receiver.recv_timeout(Duration::from_millis(1500)),
+        Err(RecvTimeoutError::Timeout)
+    );
+
+    // Once we queue a normal job, things start.
+    at.queue_hi(|_shelf| {});
+    assert_eq!(0, idle_receiver.recv_timeout(Duration::from_millis(200)).unwrap());
+
+    // The idle callback queues a job, and completion of that job
+    // means the task is going idle again...so the idle callback will
+    // be called repeatedly.
+    assert_eq!(1, idle_receiver.recv_timeout(Duration::from_millis(100)).unwrap());
+    assert_eq!(2, idle_receiver.recv_timeout(Duration::from_millis(100)).unwrap());
+    assert_eq!(3, idle_receiver.recv_timeout(Duration::from_millis(100)).unwrap());
+}
+
+#[test]
+#[should_panic]
+fn test_async_task_idle_panic() {
+    let at = AsyncTask::new(Duration::from_secs(1));
+    let (idle_sender, idle_receiver) = sync_channel::<()>(3);
+    // Add an idle callback that panics.
+    at.add_idle(move |_shelf| {
+        idle_sender.send(()).unwrap();
+        panic!("Panic from idle callback");
+    });
+    // Queue a job to trigger idleness and ensuing panic.
+    at.queue_hi(|_shelf| {});
+    idle_receiver.recv().unwrap();
+
+    // Queue another job afterwards to ensure that the async thread gets joined
+    // and the panic detected.
+    let (done_sender, done_receiver) = channel();
+    at.queue_hi(move |_shelf| {
+        done_sender.send(()).unwrap();
+    });
+    done_receiver.recv().unwrap();
+}
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index a9a1c4b..754dd9c 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -45,6 +45,9 @@
 pub(crate) mod utils;
 mod versioning;
 
+#[cfg(test)]
+pub mod tests;
+
 use crate::gc::Gc;
 use crate::impl_metadata; // This is in database/utils.rs
 use crate::key_parameter::{KeyParameter, KeyParameterValue, Tag};
@@ -2864,2620 +2867,3 @@
         Ok(app_uids_vec)
     }
 }
-
-#[cfg(test)]
-pub mod tests {
-
-    use super::*;
-    use crate::key_parameter::{
-        Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
-        KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
-    };
-    use crate::key_perm_set;
-    use crate::permission::{KeyPerm, KeyPermSet};
-    use crate::super_key::{SuperKeyManager, USER_AFTER_FIRST_UNLOCK_SUPER_KEY, SuperEncryptionAlgorithm, SuperKeyType};
-    use keystore2_test_utils::TempDir;
-    use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
-        HardwareAuthToken::HardwareAuthToken,
-        HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
-    };
-    use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
-        Timestamp::Timestamp,
-    };
-    use std::cell::RefCell;
-    use std::collections::BTreeMap;
-    use std::fmt::Write;
-    use std::sync::atomic::{AtomicU8, Ordering};
-    use std::sync::Arc;
-    use std::thread;
-    use std::time::{Duration, SystemTime};
-    use crate::utils::AesGcm;
-    #[cfg(disabled)]
-    use std::time::Instant;
-
-    pub fn new_test_db() -> Result<KeystoreDB> {
-        let conn = KeystoreDB::make_connection("file::memory:")?;
-
-        let mut db = KeystoreDB { conn, gc: None, perboot: Arc::new(perboot::PerbootDB::new()) };
-        db.with_transaction(Immediate("TX_new_test_db"), |tx| {
-            KeystoreDB::init_tables(tx).context("Failed to initialize tables.").no_gc()
-        })?;
-        Ok(db)
-    }
-
-    fn rebind_alias(
-        db: &mut KeystoreDB,
-        newid: &KeyIdGuard,
-        alias: &str,
-        domain: Domain,
-        namespace: i64,
-    ) -> Result<bool> {
-        db.with_transaction(Immediate("TX_rebind_alias"), |tx| {
-            KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace, KeyType::Client).no_gc()
-        })
-        .context(ks_err!())
-    }
-
-    #[test]
-    fn datetime() -> Result<()> {
-        let conn = Connection::open_in_memory()?;
-        conn.execute("CREATE TABLE test (ts DATETIME);", [])?;
-        let now = SystemTime::now();
-        let duration = Duration::from_secs(1000);
-        let then = now.checked_sub(duration).unwrap();
-        let soon = now.checked_add(duration).unwrap();
-        conn.execute(
-            "INSERT INTO test (ts) VALUES (?), (?), (?);",
-            params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
-        )?;
-        let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
-        let mut rows = stmt.query([])?;
-        assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
-        assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
-        assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
-        assert!(rows.next()?.is_none());
-        assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
-        assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
-        assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
-        Ok(())
-    }
-
-    // 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);
-        }
-    }
-
-    // Test that we have the correct tables.
-    #[test]
-    fn test_tables() -> Result<()> {
-        let db = new_test_db()?;
-        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(), 6);
-        assert_eq!(tables[0], "blobentry");
-        assert_eq!(tables[1], "blobmetadata");
-        assert_eq!(tables[2], "grant");
-        assert_eq!(tables[3], "keyentry");
-        assert_eq!(tables[4], "keymetadata");
-        assert_eq!(tables[5], "keyparameter");
-        Ok(())
-    }
-
-    #[test]
-    fn test_auth_token_table_invariant() -> Result<()> {
-        let mut db = new_test_db()?;
-        let auth_token1 = HardwareAuthToken {
-            challenge: i64::MAX,
-            userId: 200,
-            authenticatorId: 200,
-            authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
-            timestamp: Timestamp { milliSeconds: 500 },
-            mac: String::from("mac").into_bytes(),
-        };
-        db.insert_auth_token(&auth_token1);
-        let auth_tokens_returned = get_auth_tokens(&db);
-        assert_eq!(auth_tokens_returned.len(), 1);
-
-        // insert another auth token with the same values for the columns in the UNIQUE constraint
-        // of the auth token table and different value for timestamp
-        let auth_token2 = HardwareAuthToken {
-            challenge: i64::MAX,
-            userId: 200,
-            authenticatorId: 200,
-            authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
-            timestamp: Timestamp { milliSeconds: 600 },
-            mac: String::from("mac").into_bytes(),
-        };
-
-        db.insert_auth_token(&auth_token2);
-        let mut auth_tokens_returned = get_auth_tokens(&db);
-        assert_eq!(auth_tokens_returned.len(), 1);
-
-        if let Some(auth_token) = auth_tokens_returned.pop() {
-            assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
-        }
-
-        // insert another auth token with the different values for the columns in the UNIQUE
-        // constraint of the auth token table
-        let auth_token3 = HardwareAuthToken {
-            challenge: i64::MAX,
-            userId: 201,
-            authenticatorId: 200,
-            authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
-            timestamp: Timestamp { milliSeconds: 600 },
-            mac: String::from("mac").into_bytes(),
-        };
-
-        db.insert_auth_token(&auth_token3);
-        let auth_tokens_returned = get_auth_tokens(&db);
-        assert_eq!(auth_tokens_returned.len(), 2);
-
-        Ok(())
-    }
-
-    // utility function for test_auth_token_table_invariant()
-    fn get_auth_tokens(db: &KeystoreDB) -> Vec<AuthTokenEntry> {
-        db.perboot.get_all_auth_token_entries()
-    }
-
-    fn create_key_entry(
-        db: &mut KeystoreDB,
-        domain: &Domain,
-        namespace: &i64,
-        key_type: KeyType,
-        km_uuid: &Uuid,
-    ) -> Result<KeyIdGuard> {
-        db.with_transaction(Immediate("TX_create_key_entry"), |tx| {
-            KeystoreDB::create_key_entry_internal(tx, domain, namespace, key_type, km_uuid).no_gc()
-        })
-    }
-
-    #[test]
-    fn test_persistence_for_files() -> Result<()> {
-        let temp_dir = TempDir::new("persistent_db_test")?;
-        let mut db = KeystoreDB::new(temp_dir.path(), None)?;
-
-        create_key_entry(&mut db, &Domain::APP, &100, KeyType::Client, &KEYSTORE_UUID)?;
-        let entries = get_keyentry(&db)?;
-        assert_eq!(entries.len(), 1);
-
-        let db = KeystoreDB::new(temp_dir.path(), None)?;
-
-        let entries_new = get_keyentry(&db)?;
-        assert_eq!(entries, entries_new);
-        Ok(())
-    }
-
-    #[test]
-    fn test_create_key_entry() -> Result<()> {
-        fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
-            (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
-        }
-
-        let mut db = new_test_db()?;
-
-        create_key_entry(&mut db, &Domain::APP, &100, KeyType::Client, &KEYSTORE_UUID)?;
-        create_key_entry(&mut db, &Domain::SELINUX, &101, KeyType::Client, &KEYSTORE_UUID)?;
-
-        let entries = get_keyentry(&db)?;
-        assert_eq!(entries.len(), 2);
-        assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
-        assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
-
-        // Test that we must pass in a valid Domain.
-        check_result_is_error_containing_string(
-            create_key_entry(&mut db, &Domain::GRANT, &102, KeyType::Client, &KEYSTORE_UUID),
-            &format!("Domain {:?} must be either App or SELinux.", Domain::GRANT),
-        );
-        check_result_is_error_containing_string(
-            create_key_entry(&mut db, &Domain::BLOB, &103, KeyType::Client, &KEYSTORE_UUID),
-            &format!("Domain {:?} must be either App or SELinux.", Domain::BLOB),
-        );
-        check_result_is_error_containing_string(
-            create_key_entry(&mut db, &Domain::KEY_ID, &104, KeyType::Client, &KEYSTORE_UUID),
-            &format!("Domain {:?} must be either App or SELinux.", Domain::KEY_ID),
-        );
-
-        Ok(())
-    }
-
-    #[test]
-    fn test_rebind_alias() -> Result<()> {
-        fn extractor(
-            ke: &KeyEntryRow,
-        ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
-            (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
-        }
-
-        let mut db = new_test_db()?;
-        create_key_entry(&mut db, &Domain::APP, &42, KeyType::Client, &KEYSTORE_UUID)?;
-        create_key_entry(&mut db, &Domain::APP, &42, KeyType::Client, &KEYSTORE_UUID)?;
-        let entries = get_keyentry(&db)?;
-        assert_eq!(entries.len(), 2);
-        assert_eq!(
-            extractor(&entries[0]),
-            (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
-        );
-        assert_eq!(
-            extractor(&entries[1]),
-            (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
-        );
-
-        // Test that the first call to rebind_alias sets the alias.
-        rebind_alias(&mut db, &KEY_ID_LOCK.get(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"), Some(KEYSTORE_UUID))
-        );
-        assert_eq!(
-            extractor(&entries[1]),
-            (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
-        );
-
-        // Test that the second call to rebind_alias also empties the old one.
-        rebind_alias(&mut db, &KEY_ID_LOCK.get(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, Some(KEYSTORE_UUID)));
-        assert_eq!(
-            extractor(&entries[1]),
-            (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
-        );
-
-        // Test that we must pass in a valid Domain.
-        check_result_is_error_containing_string(
-            rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
-            &format!("Domain {:?} must be either App or SELinux.", Domain::GRANT),
-        );
-        check_result_is_error_containing_string(
-            rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
-            &format!("Domain {:?} must be either App or SELinux.", Domain::BLOB),
-        );
-        check_result_is_error_containing_string(
-            rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
-            &format!("Domain {:?} must be either App or SELinux.", Domain::KEY_ID),
-        );
-
-        // Test that we correctly handle setting an alias for something that does not exist.
-        check_result_is_error_containing_string(
-            rebind_alias(&mut db, &KEY_ID_LOCK.get(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, Some(KEYSTORE_UUID)));
-        assert_eq!(
-            extractor(&entries[1]),
-            (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
-        );
-
-        Ok(())
-    }
-
-    #[test]
-    fn test_grant_ungrant() -> Result<()> {
-        const CALLER_UID: u32 = 15;
-        const GRANTEE_UID: u32 = 12;
-        const SELINUX_NAMESPACE: i64 = 7;
-
-        let mut db = new_test_db()?;
-        db.conn.execute(
-            "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
-                VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
-            params![KEYSTORE_UUID, KEYSTORE_UUID],
-        )?;
-        let app_key = KeyDescriptor {
-            domain: super::Domain::APP,
-            nspace: 0,
-            alias: Some("key".to_string()),
-            blob: None,
-        };
-        const PVEC1: KeyPermSet = key_perm_set![KeyPerm::Use, KeyPerm::GetInfo];
-        const PVEC2: KeyPermSet = key_perm_set![KeyPerm::Use];
-
-        // Reset totally predictable random number generator in case we
-        // are not the first test running on this thread.
-        reset_random();
-        let next_random = 0i64;
-
-        let app_granted_key = db
-            .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
-                assert_eq!(*a, PVEC1);
-                assert_eq!(
-                    *k,
-                    KeyDescriptor {
-                        domain: super::Domain::APP,
-                        // namespace must be set to the caller_uid.
-                        nspace: CALLER_UID as i64,
-                        alias: Some("key".to_string()),
-                        blob: None,
-                    }
-                );
-                Ok(())
-            })
-            .unwrap();
-
-        assert_eq!(
-            app_granted_key,
-            KeyDescriptor {
-                domain: super::Domain::GRANT,
-                // The grantid is next_random due to the mock random number generator.
-                nspace: next_random,
-                alias: None,
-                blob: None,
-            }
-        );
-
-        let selinux_key = KeyDescriptor {
-            domain: super::Domain::SELINUX,
-            nspace: SELINUX_NAMESPACE,
-            alias: Some("yek".to_string()),
-            blob: None,
-        };
-
-        let selinux_granted_key = db
-            .grant(&selinux_key, CALLER_UID, 12, PVEC1, |k, a| {
-                assert_eq!(*a, PVEC1);
-                assert_eq!(
-                    *k,
-                    KeyDescriptor {
-                        domain: super::Domain::SELINUX,
-                        // namespace must be the supplied SELinux
-                        // namespace.
-                        nspace: SELINUX_NAMESPACE,
-                        alias: Some("yek".to_string()),
-                        blob: None,
-                    }
-                );
-                Ok(())
-            })
-            .unwrap();
-
-        assert_eq!(
-            selinux_granted_key,
-            KeyDescriptor {
-                domain: super::Domain::GRANT,
-                // The grantid is next_random + 1 due to the mock random number generator.
-                nspace: next_random + 1,
-                alias: None,
-                blob: None,
-            }
-        );
-
-        // This should update the existing grant with PVEC2.
-        let selinux_granted_key = db
-            .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
-                assert_eq!(*a, PVEC2);
-                assert_eq!(
-                    *k,
-                    KeyDescriptor {
-                        domain: super::Domain::SELINUX,
-                        // namespace must be the supplied SELinux
-                        // namespace.
-                        nspace: SELINUX_NAMESPACE,
-                        alias: Some("yek".to_string()),
-                        blob: None,
-                    }
-                );
-                Ok(())
-            })
-            .unwrap();
-
-        assert_eq!(
-            selinux_granted_key,
-            KeyDescriptor {
-                domain: super::Domain::GRANT,
-                // Same grant id as before. The entry was only updated.
-                nspace: next_random + 1,
-                alias: None,
-                blob: None,
-            }
-        );
-
-        {
-            // Limiting scope of stmt, because it borrows db.
-            let mut stmt = db
-                .conn
-                .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
-            let mut rows = stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>([], |row| {
-                Ok((row.get(0)?, row.get(1)?, row.get(2)?, KeyPermSet::from(row.get::<_, i32>(3)?)))
-            })?;
-
-            let r = rows.next().unwrap().unwrap();
-            assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
-            let r = rows.next().unwrap().unwrap();
-            assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
-            assert!(rows.next().is_none());
-        }
-
-        debug_dump_keyentry_table(&mut db)?;
-        println!("app_key {:?}", app_key);
-        println!("selinux_key {:?}", selinux_key);
-
-        db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
-        db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
-
-        Ok(())
-    }
-
-    static TEST_KEY_BLOB: &[u8] = b"my test blob";
-    static TEST_CERT_BLOB: &[u8] = b"my test cert";
-    static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
-
-    #[test]
-    fn test_set_blob() -> Result<()> {
-        let key_id = KEY_ID_LOCK.get(3000);
-        let mut db = new_test_db()?;
-        let mut blob_metadata = BlobMetaData::new();
-        blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
-        db.set_blob(
-            &key_id,
-            SubComponentType::KEY_BLOB,
-            Some(TEST_KEY_BLOB),
-            Some(&blob_metadata),
-        )?;
-        db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
-        db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
-        drop(key_id);
-
-        let mut stmt = db.conn.prepare(
-            "SELECT subcomponent_type, keyentryid, blob, id FROM persistent.blobentry
-                ORDER BY subcomponent_type ASC;",
-        )?;
-        let mut rows = stmt
-            .query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>([], |row| {
-                Ok(((row.get(0)?, row.get(1)?, row.get(2)?), row.get(3)?))
-            })?;
-        let (r, id) = rows.next().unwrap().unwrap();
-        assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
-        let (r, _) = rows.next().unwrap().unwrap();
-        assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
-        let (r, _) = rows.next().unwrap().unwrap();
-        assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
-
-        drop(rows);
-        drop(stmt);
-
-        assert_eq!(
-            db.with_transaction(Immediate("TX_test"), |tx| {
-                BlobMetaData::load_from_db(id, tx).no_gc()
-            })
-            .expect("Should find blob metadata."),
-            blob_metadata
-        );
-        Ok(())
-    }
-
-    static TEST_ALIAS: &str = "my super duper key";
-
-    #[test]
-    fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
-        let mut db = new_test_db()?;
-        let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
-            .context("test_insert_and_load_full_keyentry_domain_app")?
-            .0;
-        let (_key_guard, key_entry) = db
-            .load_key_entry(
-                &KeyDescriptor {
-                    domain: Domain::APP,
-                    nspace: 0,
-                    alias: Some(TEST_ALIAS.to_string()),
-                    blob: None,
-                },
-                KeyType::Client,
-                KeyEntryLoadBits::BOTH,
-                1,
-                |_k, _av| Ok(()),
-            )
-            .unwrap();
-        assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
-
-        db.unbind_key(
-            &KeyDescriptor {
-                domain: Domain::APP,
-                nspace: 0,
-                alias: Some(TEST_ALIAS.to_string()),
-                blob: None,
-            },
-            KeyType::Client,
-            1,
-            |_, _| Ok(()),
-        )
-        .unwrap();
-
-        assert_eq!(
-            Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
-            db.load_key_entry(
-                &KeyDescriptor {
-                    domain: Domain::APP,
-                    nspace: 0,
-                    alias: Some(TEST_ALIAS.to_string()),
-                    blob: None,
-                },
-                KeyType::Client,
-                KeyEntryLoadBits::NONE,
-                1,
-                |_k, _av| Ok(()),
-            )
-            .unwrap_err()
-            .root_cause()
-            .downcast_ref::<KsError>()
-        );
-
-        Ok(())
-    }
-
-    #[test]
-    fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
-        let mut db = new_test_db()?;
-
-        db.store_new_certificate(
-            &KeyDescriptor {
-                domain: Domain::APP,
-                nspace: 1,
-                alias: Some(TEST_ALIAS.to_string()),
-                blob: None,
-            },
-            KeyType::Client,
-            TEST_CERT_BLOB,
-            &KEYSTORE_UUID,
-        )
-        .expect("Trying to insert cert.");
-
-        let (_key_guard, mut key_entry) = db
-            .load_key_entry(
-                &KeyDescriptor {
-                    domain: Domain::APP,
-                    nspace: 1,
-                    alias: Some(TEST_ALIAS.to_string()),
-                    blob: None,
-                },
-                KeyType::Client,
-                KeyEntryLoadBits::PUBLIC,
-                1,
-                |_k, _av| Ok(()),
-            )
-            .expect("Trying to read certificate entry.");
-
-        assert!(key_entry.pure_cert());
-        assert!(key_entry.cert().is_none());
-        assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
-
-        db.unbind_key(
-            &KeyDescriptor {
-                domain: Domain::APP,
-                nspace: 1,
-                alias: Some(TEST_ALIAS.to_string()),
-                blob: None,
-            },
-            KeyType::Client,
-            1,
-            |_, _| Ok(()),
-        )
-        .unwrap();
-
-        assert_eq!(
-            Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
-            db.load_key_entry(
-                &KeyDescriptor {
-                    domain: Domain::APP,
-                    nspace: 1,
-                    alias: Some(TEST_ALIAS.to_string()),
-                    blob: None,
-                },
-                KeyType::Client,
-                KeyEntryLoadBits::NONE,
-                1,
-                |_k, _av| Ok(()),
-            )
-            .unwrap_err()
-            .root_cause()
-            .downcast_ref::<KsError>()
-        );
-
-        Ok(())
-    }
-
-    #[test]
-    fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
-        let mut db = new_test_db()?;
-        let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
-            .context("test_insert_and_load_full_keyentry_domain_selinux")?
-            .0;
-        let (_key_guard, key_entry) = db
-            .load_key_entry(
-                &KeyDescriptor {
-                    domain: Domain::SELINUX,
-                    nspace: 1,
-                    alias: Some(TEST_ALIAS.to_string()),
-                    blob: None,
-                },
-                KeyType::Client,
-                KeyEntryLoadBits::BOTH,
-                1,
-                |_k, _av| Ok(()),
-            )
-            .unwrap();
-        assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
-
-        db.unbind_key(
-            &KeyDescriptor {
-                domain: Domain::SELINUX,
-                nspace: 1,
-                alias: Some(TEST_ALIAS.to_string()),
-                blob: None,
-            },
-            KeyType::Client,
-            1,
-            |_, _| Ok(()),
-        )
-        .unwrap();
-
-        assert_eq!(
-            Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
-            db.load_key_entry(
-                &KeyDescriptor {
-                    domain: Domain::SELINUX,
-                    nspace: 1,
-                    alias: Some(TEST_ALIAS.to_string()),
-                    blob: None,
-                },
-                KeyType::Client,
-                KeyEntryLoadBits::NONE,
-                1,
-                |_k, _av| Ok(()),
-            )
-            .unwrap_err()
-            .root_cause()
-            .downcast_ref::<KsError>()
-        );
-
-        Ok(())
-    }
-
-    #[test]
-    fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
-        let mut db = new_test_db()?;
-        let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
-            .context("test_insert_and_load_full_keyentry_domain_key_id")?
-            .0;
-        let (_, key_entry) = db
-            .load_key_entry(
-                &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
-                KeyType::Client,
-                KeyEntryLoadBits::BOTH,
-                1,
-                |_k, _av| Ok(()),
-            )
-            .unwrap();
-
-        assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
-
-        db.unbind_key(
-            &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
-            KeyType::Client,
-            1,
-            |_, _| Ok(()),
-        )
-        .unwrap();
-
-        assert_eq!(
-            Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
-            db.load_key_entry(
-                &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
-                KeyType::Client,
-                KeyEntryLoadBits::NONE,
-                1,
-                |_k, _av| Ok(()),
-            )
-            .unwrap_err()
-            .root_cause()
-            .downcast_ref::<KsError>()
-        );
-
-        Ok(())
-    }
-
-    #[test]
-    fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
-        let mut db = new_test_db()?;
-        let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
-            .context("test_check_and_update_key_usage_count_with_limited_use_key")?
-            .0;
-        // Update the usage count of the limited use key.
-        db.check_and_update_key_usage_count(key_id)?;
-
-        let (_key_guard, key_entry) = db.load_key_entry(
-            &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
-            KeyType::Client,
-            KeyEntryLoadBits::BOTH,
-            1,
-            |_k, _av| Ok(()),
-        )?;
-
-        // The usage count is decremented now.
-        assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
-
-        Ok(())
-    }
-
-    #[test]
-    fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
-        let mut db = new_test_db()?;
-        let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
-            .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
-            .0;
-        // Update the usage count of the limited use key.
-        db.check_and_update_key_usage_count(key_id).expect(concat!(
-            "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
-            "This should succeed."
-        ));
-
-        // Try to update the exhausted limited use key.
-        let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
-            "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
-            "This should fail."
-        ));
-        assert_eq!(
-            &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
-            e.root_cause().downcast_ref::<KsError>().unwrap()
-        );
-
-        Ok(())
-    }
-
-    #[test]
-    fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
-        let mut db = new_test_db()?;
-        let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
-            .context("test_insert_and_load_full_keyentry_from_grant")?
-            .0;
-
-        let granted_key = db
-            .grant(
-                &KeyDescriptor {
-                    domain: Domain::APP,
-                    nspace: 0,
-                    alias: Some(TEST_ALIAS.to_string()),
-                    blob: None,
-                },
-                1,
-                2,
-                key_perm_set![KeyPerm::Use],
-                |_k, _av| Ok(()),
-            )
-            .unwrap();
-
-        debug_dump_grant_table(&mut db)?;
-
-        let (_key_guard, key_entry) = db
-            .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
-                assert_eq!(Domain::GRANT, k.domain);
-                assert!(av.unwrap().includes(KeyPerm::Use));
-                Ok(())
-            })
-            .unwrap();
-
-        assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
-
-        db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
-
-        assert_eq!(
-            Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
-            db.load_key_entry(
-                &granted_key,
-                KeyType::Client,
-                KeyEntryLoadBits::NONE,
-                2,
-                |_k, _av| Ok(()),
-            )
-            .unwrap_err()
-            .root_cause()
-            .downcast_ref::<KsError>()
-        );
-
-        Ok(())
-    }
-
-    // This test attempts to load a key by key id while the caller is not the owner
-    // but a grant exists for the given key and the caller.
-    #[test]
-    fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
-        let mut db = new_test_db()?;
-        const OWNER_UID: u32 = 1u32;
-        const GRANTEE_UID: u32 = 2u32;
-        const SOMEONE_ELSE_UID: u32 = 3u32;
-        let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
-            .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
-            .0;
-
-        db.grant(
-            &KeyDescriptor {
-                domain: Domain::APP,
-                nspace: 0,
-                alias: Some(TEST_ALIAS.to_string()),
-                blob: None,
-            },
-            OWNER_UID,
-            GRANTEE_UID,
-            key_perm_set![KeyPerm::Use],
-            |_k, _av| Ok(()),
-        )
-        .unwrap();
-
-        debug_dump_grant_table(&mut db)?;
-
-        let id_descriptor =
-            KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
-
-        let (_, key_entry) = db
-            .load_key_entry(
-                &id_descriptor,
-                KeyType::Client,
-                KeyEntryLoadBits::BOTH,
-                GRANTEE_UID,
-                |k, av| {
-                    assert_eq!(Domain::APP, k.domain);
-                    assert_eq!(OWNER_UID as i64, k.nspace);
-                    assert!(av.unwrap().includes(KeyPerm::Use));
-                    Ok(())
-                },
-            )
-            .unwrap();
-
-        assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
-
-        let (_, key_entry) = db
-            .load_key_entry(
-                &id_descriptor,
-                KeyType::Client,
-                KeyEntryLoadBits::BOTH,
-                SOMEONE_ELSE_UID,
-                |k, av| {
-                    assert_eq!(Domain::APP, k.domain);
-                    assert_eq!(OWNER_UID as i64, k.nspace);
-                    assert!(av.is_none());
-                    Ok(())
-                },
-            )
-            .unwrap();
-
-        assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
-
-        db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
-
-        assert_eq!(
-            Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
-            db.load_key_entry(
-                &id_descriptor,
-                KeyType::Client,
-                KeyEntryLoadBits::NONE,
-                GRANTEE_UID,
-                |_k, _av| Ok(()),
-            )
-            .unwrap_err()
-            .root_cause()
-            .downcast_ref::<KsError>()
-        );
-
-        Ok(())
-    }
-
-    // Creates a key migrates it to a different location and then tries to access it by the old
-    // and new location.
-    #[test]
-    fn test_migrate_key_app_to_app() -> Result<()> {
-        let mut db = new_test_db()?;
-        const SOURCE_UID: u32 = 1u32;
-        const DESTINATION_UID: u32 = 2u32;
-        static SOURCE_ALIAS: &str = "SOURCE_ALIAS";
-        static DESTINATION_ALIAS: &str = "DESTINATION_ALIAS";
-        let key_id_guard =
-            make_test_key_entry(&mut db, Domain::APP, SOURCE_UID as i64, SOURCE_ALIAS, None)
-                .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
-
-        let source_descriptor: KeyDescriptor = KeyDescriptor {
-            domain: Domain::APP,
-            nspace: -1,
-            alias: Some(SOURCE_ALIAS.to_string()),
-            blob: None,
-        };
-
-        let destination_descriptor: KeyDescriptor = KeyDescriptor {
-            domain: Domain::APP,
-            nspace: -1,
-            alias: Some(DESTINATION_ALIAS.to_string()),
-            blob: None,
-        };
-
-        let key_id = key_id_guard.id();
-
-        db.migrate_key_namespace(key_id_guard, &destination_descriptor, DESTINATION_UID, |_k| {
-            Ok(())
-        })
-        .unwrap();
-
-        let (_, key_entry) = db
-            .load_key_entry(
-                &destination_descriptor,
-                KeyType::Client,
-                KeyEntryLoadBits::BOTH,
-                DESTINATION_UID,
-                |k, av| {
-                    assert_eq!(Domain::APP, k.domain);
-                    assert_eq!(DESTINATION_UID as i64, k.nspace);
-                    assert!(av.is_none());
-                    Ok(())
-                },
-            )
-            .unwrap();
-
-        assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
-
-        assert_eq!(
-            Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
-            db.load_key_entry(
-                &source_descriptor,
-                KeyType::Client,
-                KeyEntryLoadBits::NONE,
-                SOURCE_UID,
-                |_k, _av| Ok(()),
-            )
-            .unwrap_err()
-            .root_cause()
-            .downcast_ref::<KsError>()
-        );
-
-        Ok(())
-    }
-
-    // Creates a key migrates it to a different location and then tries to access it by the old
-    // and new location.
-    #[test]
-    fn test_migrate_key_app_to_selinux() -> Result<()> {
-        let mut db = new_test_db()?;
-        const SOURCE_UID: u32 = 1u32;
-        const DESTINATION_UID: u32 = 2u32;
-        const DESTINATION_NAMESPACE: i64 = 1000i64;
-        static SOURCE_ALIAS: &str = "SOURCE_ALIAS";
-        static DESTINATION_ALIAS: &str = "DESTINATION_ALIAS";
-        let key_id_guard =
-            make_test_key_entry(&mut db, Domain::APP, SOURCE_UID as i64, SOURCE_ALIAS, None)
-                .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
-
-        let source_descriptor: KeyDescriptor = KeyDescriptor {
-            domain: Domain::APP,
-            nspace: -1,
-            alias: Some(SOURCE_ALIAS.to_string()),
-            blob: None,
-        };
-
-        let destination_descriptor: KeyDescriptor = KeyDescriptor {
-            domain: Domain::SELINUX,
-            nspace: DESTINATION_NAMESPACE,
-            alias: Some(DESTINATION_ALIAS.to_string()),
-            blob: None,
-        };
-
-        let key_id = key_id_guard.id();
-
-        db.migrate_key_namespace(key_id_guard, &destination_descriptor, DESTINATION_UID, |_k| {
-            Ok(())
-        })
-        .unwrap();
-
-        let (_, key_entry) = db
-            .load_key_entry(
-                &destination_descriptor,
-                KeyType::Client,
-                KeyEntryLoadBits::BOTH,
-                DESTINATION_UID,
-                |k, av| {
-                    assert_eq!(Domain::SELINUX, k.domain);
-                    assert_eq!(DESTINATION_NAMESPACE, k.nspace);
-                    assert!(av.is_none());
-                    Ok(())
-                },
-            )
-            .unwrap();
-
-        assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
-
-        assert_eq!(
-            Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
-            db.load_key_entry(
-                &source_descriptor,
-                KeyType::Client,
-                KeyEntryLoadBits::NONE,
-                SOURCE_UID,
-                |_k, _av| Ok(()),
-            )
-            .unwrap_err()
-            .root_cause()
-            .downcast_ref::<KsError>()
-        );
-
-        Ok(())
-    }
-
-    // Creates two keys and tries to migrate the first to the location of the second which
-    // is expected to fail.
-    #[test]
-    fn test_migrate_key_destination_occupied() -> Result<()> {
-        let mut db = new_test_db()?;
-        const SOURCE_UID: u32 = 1u32;
-        const DESTINATION_UID: u32 = 2u32;
-        static SOURCE_ALIAS: &str = "SOURCE_ALIAS";
-        static DESTINATION_ALIAS: &str = "DESTINATION_ALIAS";
-        let key_id_guard =
-            make_test_key_entry(&mut db, Domain::APP, SOURCE_UID as i64, SOURCE_ALIAS, None)
-                .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
-        make_test_key_entry(&mut db, Domain::APP, DESTINATION_UID as i64, DESTINATION_ALIAS, None)
-            .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
-
-        let destination_descriptor: KeyDescriptor = KeyDescriptor {
-            domain: Domain::APP,
-            nspace: -1,
-            alias: Some(DESTINATION_ALIAS.to_string()),
-            blob: None,
-        };
-
-        assert_eq!(
-            Some(&KsError::Rc(ResponseCode::INVALID_ARGUMENT)),
-            db.migrate_key_namespace(
-                key_id_guard,
-                &destination_descriptor,
-                DESTINATION_UID,
-                |_k| Ok(())
-            )
-            .unwrap_err()
-            .root_cause()
-            .downcast_ref::<KsError>()
-        );
-
-        Ok(())
-    }
-
-    #[test]
-    fn test_upgrade_0_to_1() {
-        const ALIAS1: &str = "test_upgrade_0_to_1_1";
-        const ALIAS2: &str = "test_upgrade_0_to_1_2";
-        const ALIAS3: &str = "test_upgrade_0_to_1_3";
-        const UID: u32 = 33;
-        let temp_dir = Arc::new(TempDir::new("test_upgrade_0_to_1").unwrap());
-        let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
-        let key_id_untouched1 =
-            make_test_key_entry(&mut db, Domain::APP, UID as i64, ALIAS1, None).unwrap().id();
-        let key_id_untouched2 =
-            make_bootlevel_key_entry(&mut db, Domain::APP, UID as i64, ALIAS2, false).unwrap().id();
-        let key_id_deleted =
-            make_bootlevel_key_entry(&mut db, Domain::APP, UID as i64, ALIAS3, true).unwrap().id();
-
-        let (_, key_entry) = db
-            .load_key_entry(
-                &KeyDescriptor {
-                    domain: Domain::APP,
-                    nspace: -1,
-                    alias: Some(ALIAS1.to_string()),
-                    blob: None,
-                },
-                KeyType::Client,
-                KeyEntryLoadBits::BOTH,
-                UID,
-                |k, av| {
-                    assert_eq!(Domain::APP, k.domain);
-                    assert_eq!(UID as i64, k.nspace);
-                    assert!(av.is_none());
-                    Ok(())
-                },
-            )
-            .unwrap();
-        assert_eq!(key_entry, make_test_key_entry_test_vector(key_id_untouched1, None));
-        let (_, key_entry) = db
-            .load_key_entry(
-                &KeyDescriptor {
-                    domain: Domain::APP,
-                    nspace: -1,
-                    alias: Some(ALIAS2.to_string()),
-                    blob: None,
-                },
-                KeyType::Client,
-                KeyEntryLoadBits::BOTH,
-                UID,
-                |k, av| {
-                    assert_eq!(Domain::APP, k.domain);
-                    assert_eq!(UID as i64, k.nspace);
-                    assert!(av.is_none());
-                    Ok(())
-                },
-            )
-            .unwrap();
-        assert_eq!(key_entry, make_bootlevel_test_key_entry_test_vector(key_id_untouched2, false));
-        let (_, key_entry) = db
-            .load_key_entry(
-                &KeyDescriptor {
-                    domain: Domain::APP,
-                    nspace: -1,
-                    alias: Some(ALIAS3.to_string()),
-                    blob: None,
-                },
-                KeyType::Client,
-                KeyEntryLoadBits::BOTH,
-                UID,
-                |k, av| {
-                    assert_eq!(Domain::APP, k.domain);
-                    assert_eq!(UID as i64, k.nspace);
-                    assert!(av.is_none());
-                    Ok(())
-                },
-            )
-            .unwrap();
-        assert_eq!(key_entry, make_bootlevel_test_key_entry_test_vector(key_id_deleted, true));
-
-        db.with_transaction(Immediate("TX_test"), |tx| KeystoreDB::from_0_to_1(tx).no_gc())
-            .unwrap();
-
-        let (_, key_entry) = db
-            .load_key_entry(
-                &KeyDescriptor {
-                    domain: Domain::APP,
-                    nspace: -1,
-                    alias: Some(ALIAS1.to_string()),
-                    blob: None,
-                },
-                KeyType::Client,
-                KeyEntryLoadBits::BOTH,
-                UID,
-                |k, av| {
-                    assert_eq!(Domain::APP, k.domain);
-                    assert_eq!(UID as i64, k.nspace);
-                    assert!(av.is_none());
-                    Ok(())
-                },
-            )
-            .unwrap();
-        assert_eq!(key_entry, make_test_key_entry_test_vector(key_id_untouched1, None));
-        let (_, key_entry) = db
-            .load_key_entry(
-                &KeyDescriptor {
-                    domain: Domain::APP,
-                    nspace: -1,
-                    alias: Some(ALIAS2.to_string()),
-                    blob: None,
-                },
-                KeyType::Client,
-                KeyEntryLoadBits::BOTH,
-                UID,
-                |k, av| {
-                    assert_eq!(Domain::APP, k.domain);
-                    assert_eq!(UID as i64, k.nspace);
-                    assert!(av.is_none());
-                    Ok(())
-                },
-            )
-            .unwrap();
-        assert_eq!(key_entry, make_bootlevel_test_key_entry_test_vector(key_id_untouched2, false));
-        assert_eq!(
-            Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
-            db.load_key_entry(
-                &KeyDescriptor {
-                    domain: Domain::APP,
-                    nspace: -1,
-                    alias: Some(ALIAS3.to_string()),
-                    blob: None,
-                },
-                KeyType::Client,
-                KeyEntryLoadBits::BOTH,
-                UID,
-                |k, av| {
-                    assert_eq!(Domain::APP, k.domain);
-                    assert_eq!(UID as i64, k.nspace);
-                    assert!(av.is_none());
-                    Ok(())
-                },
-            )
-            .unwrap_err()
-            .root_cause()
-            .downcast_ref::<KsError>()
-        );
-    }
-
-    static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
-
-    #[test]
-    fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
-        let handle = {
-            let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
-            let temp_dir_clone = temp_dir.clone();
-            let mut db = KeystoreDB::new(temp_dir.path(), None)?;
-            let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
-                .context("test_insert_and_load_full_keyentry_domain_app")?
-                .0;
-            let (_key_guard, key_entry) = db
-                .load_key_entry(
-                    &KeyDescriptor {
-                        domain: Domain::APP,
-                        nspace: 0,
-                        alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
-                        blob: None,
-                    },
-                    KeyType::Client,
-                    KeyEntryLoadBits::BOTH,
-                    33,
-                    |_k, _av| Ok(()),
-                )
-                .unwrap();
-            assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
-            let state = Arc::new(AtomicU8::new(1));
-            let state2 = state.clone();
-
-            // Spawning a second thread that attempts to acquire the key id lock
-            // for the same key as the primary thread. The primary thread then
-            // waits, thereby forcing the secondary thread into the second stage
-            // of acquiring the lock (see KEY ID LOCK 2/2 above).
-            // The test succeeds if the secondary thread observes the transition
-            // of `state` from 1 to 2, despite having a whole second to overtake
-            // the primary thread.
-            let handle = thread::spawn(move || {
-                let temp_dir = temp_dir_clone;
-                let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
-                assert!(db
-                    .load_key_entry(
-                        &KeyDescriptor {
-                            domain: Domain::APP,
-                            nspace: 0,
-                            alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
-                            blob: None,
-                        },
-                        KeyType::Client,
-                        KeyEntryLoadBits::BOTH,
-                        33,
-                        |_k, _av| Ok(()),
-                    )
-                    .is_ok());
-                // We should only see a 2 here because we can only return
-                // from load_key_entry when the `_key_guard` expires,
-                // which happens at the end of the scope.
-                assert_eq!(2, state2.load(Ordering::Relaxed));
-            });
-
-            thread::sleep(std::time::Duration::from_millis(1000));
-
-            assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
-
-            // Return the handle from this scope so we can join with the
-            // secondary thread after the key id lock has expired.
-            handle
-            // This is where the `_key_guard` goes out of scope,
-            // which is the reason for concurrent load_key_entry on the same key
-            // to unblock.
-        };
-        // Join with the secondary thread and unwrap, to propagate failing asserts to the
-        // main test thread. We will not see failing asserts in secondary threads otherwise.
-        handle.join().unwrap();
-        Ok(())
-    }
-
-    #[test]
-    fn test_database_busy_error_code() {
-        let temp_dir =
-            TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
-
-        let mut db1 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database1.");
-        let mut db2 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database2.");
-
-        let _tx1 = db1
-            .conn
-            .transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)
-            .expect("Failed to create first transaction.");
-
-        let error = db2
-            .conn
-            .transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)
-            .context("Transaction begin failed.")
-            .expect_err("This should fail.");
-        let root_cause = error.root_cause();
-        if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
-            root_cause.downcast_ref::<rusqlite::ffi::Error>()
-        {
-            return;
-        }
-        panic!(
-            "Unexpected error {:?} \n{:?} \n{:?}",
-            error,
-            root_cause,
-            root_cause.downcast_ref::<rusqlite::ffi::Error>()
-        )
-    }
-
-    #[cfg(disabled)]
-    #[test]
-    fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
-        let temp_dir = Arc::new(
-            TempDir::new("test_large_number_of_concurrent_db_manipulations_")
-                .expect("Failed to create temp dir."),
-        );
-
-        let test_begin = Instant::now();
-
-        const KEY_COUNT: u32 = 500u32;
-        let mut db =
-            new_test_db_with_gc(temp_dir.path(), |_, _| Ok(())).expect("Failed to open database.");
-        const OPEN_DB_COUNT: u32 = 50u32;
-
-        let mut actual_key_count = KEY_COUNT;
-        // First insert KEY_COUNT keys.
-        for count in 0..KEY_COUNT {
-            if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
-                actual_key_count = count;
-                break;
-            }
-            let alias = format!("test_alias_{}", count);
-            make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
-                .expect("Failed to make key entry.");
-        }
-
-        // Insert more keys from a different thread and into a different namespace.
-        let temp_dir1 = temp_dir.clone();
-        let handle1 = thread::spawn(move || {
-            let mut db = new_test_db_with_gc(temp_dir1.path(), |_, _| Ok(()))
-                .expect("Failed to open database.");
-
-            for count in 0..actual_key_count {
-                if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
-                    return;
-                }
-                let alias = format!("test_alias_{}", count);
-                make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
-                    .expect("Failed to make key entry.");
-            }
-
-            // then unbind them again.
-            for count in 0..actual_key_count {
-                if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
-                    return;
-                }
-                let key = KeyDescriptor {
-                    domain: Domain::APP,
-                    nspace: -1,
-                    alias: Some(format!("test_alias_{}", count)),
-                    blob: None,
-                };
-                db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
-            }
-        });
-
-        // And start unbinding the first set of keys.
-        let temp_dir2 = temp_dir.clone();
-        let handle2 = thread::spawn(move || {
-            let mut db = new_test_db_with_gc(temp_dir2.path(), |_, _| Ok(()))
-                .expect("Failed to open database.");
-
-            for count in 0..actual_key_count {
-                if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
-                    return;
-                }
-                let key = KeyDescriptor {
-                    domain: Domain::APP,
-                    nspace: -1,
-                    alias: Some(format!("test_alias_{}", count)),
-                    blob: None,
-                };
-                db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
-            }
-        });
-
-        // While a lot of inserting and deleting is going on we have to open database connections
-        // successfully and use them.
-        // This clone is not redundant, because temp_dir needs to be kept alive until db goes
-        // out of scope.
-        #[allow(clippy::redundant_clone)]
-        let temp_dir4 = temp_dir.clone();
-        let handle4 = thread::spawn(move || {
-            for count in 0..OPEN_DB_COUNT {
-                if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
-                    return;
-                }
-                let mut db = new_test_db_with_gc(temp_dir4.path(), |_, _| Ok(()))
-                    .expect("Failed to open database.");
-
-                let alias = format!("test_alias_{}", count);
-                make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
-                    .expect("Failed to make key entry.");
-                let key = KeyDescriptor {
-                    domain: Domain::APP,
-                    nspace: -1,
-                    alias: Some(alias),
-                    blob: None,
-                };
-                db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
-            }
-        });
-
-        handle1.join().expect("Thread 1 panicked.");
-        handle2.join().expect("Thread 2 panicked.");
-        handle4.join().expect("Thread 4 panicked.");
-
-        Ok(())
-    }
-
-    #[test]
-    fn list() -> Result<()> {
-        let temp_dir = TempDir::new("list_test")?;
-        let mut db = KeystoreDB::new(temp_dir.path(), None)?;
-        static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
-            (Domain::APP, 1, "test1"),
-            (Domain::APP, 1, "test2"),
-            (Domain::APP, 1, "test3"),
-            (Domain::APP, 1, "test4"),
-            (Domain::APP, 1, "test5"),
-            (Domain::APP, 1, "test6"),
-            (Domain::APP, 1, "test7"),
-            (Domain::APP, 2, "test1"),
-            (Domain::APP, 2, "test2"),
-            (Domain::APP, 2, "test3"),
-            (Domain::APP, 2, "test4"),
-            (Domain::APP, 2, "test5"),
-            (Domain::APP, 2, "test6"),
-            (Domain::APP, 2, "test8"),
-            (Domain::SELINUX, 100, "test1"),
-            (Domain::SELINUX, 100, "test2"),
-            (Domain::SELINUX, 100, "test3"),
-            (Domain::SELINUX, 100, "test4"),
-            (Domain::SELINUX, 100, "test5"),
-            (Domain::SELINUX, 100, "test6"),
-            (Domain::SELINUX, 100, "test9"),
-        ];
-
-        let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
-            .iter()
-            .map(|(domain, ns, alias)| {
-                let entry =
-                    make_test_key_entry(&mut db, *domain, *ns, alias, None).unwrap_or_else(|e| {
-                        panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
-                    });
-                (entry.id(), *ns)
-            })
-            .collect();
-
-        for (domain, namespace) in
-            &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
-        {
-            let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
-                .iter()
-                .filter_map(|(domain, ns, alias)| match ns {
-                    ns if *ns == *namespace => Some(KeyDescriptor {
-                        domain: *domain,
-                        nspace: *ns,
-                        alias: Some(alias.to_string()),
-                        blob: None,
-                    }),
-                    _ => None,
-                })
-                .collect();
-            list_o_descriptors.sort();
-            let mut list_result = db.list_past_alias(*domain, *namespace, KeyType::Client, None)?;
-            list_result.sort();
-            assert_eq!(list_o_descriptors, list_result);
-
-            let mut list_o_ids: Vec<i64> = list_o_descriptors
-                .into_iter()
-                .map(|d| {
-                    let (_, entry) = db
-                        .load_key_entry(
-                            &d,
-                            KeyType::Client,
-                            KeyEntryLoadBits::NONE,
-                            *namespace as u32,
-                            |_, _| Ok(()),
-                        )
-                        .unwrap();
-                    entry.id()
-                })
-                .collect();
-            list_o_ids.sort_unstable();
-            let mut loaded_entries: Vec<i64> = list_o_keys
-                .iter()
-                .filter_map(|(id, ns)| match ns {
-                    ns if *ns == *namespace => Some(*id),
-                    _ => None,
-                })
-                .collect();
-            loaded_entries.sort_unstable();
-            assert_eq!(list_o_ids, loaded_entries);
-        }
-        assert_eq!(
-            Vec::<KeyDescriptor>::new(),
-            db.list_past_alias(Domain::SELINUX, 101, KeyType::Client, None)?
-        );
-
-        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)]
-    struct KeyEntryRow {
-        id: i64,
-        key_type: KeyType,
-        domain: Option<Domain>,
-        namespace: Option<i64>,
-        alias: Option<String>,
-        state: KeyLifeCycle,
-        km_uuid: Option<Uuid>,
-    }
-
-    fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
-        db.conn
-            .prepare("SELECT * FROM persistent.keyentry;")?
-            .query_map([], |row| {
-                Ok(KeyEntryRow {
-                    id: row.get(0)?,
-                    key_type: row.get(1)?,
-                    domain: row.get::<_, Option<_>>(2)?.map(Domain),
-                    namespace: row.get(3)?,
-                    alias: row.get(4)?,
-                    state: row.get(5)?,
-                    km_uuid: row.get(6)?,
-                })
-            })?
-            .map(|r| r.context("Could not read keyentry row."))
-            .collect::<Result<Vec<_>>>()
-    }
-
-    fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
-        make_test_params_with_sids(max_usage_count, &[42])
-    }
-
-    // Note: The parameters and SecurityLevel associations are nonsensical. This
-    // collection is only used to check if the parameters are preserved as expected by the
-    // database.
-    fn make_test_params_with_sids(
-        max_usage_count: Option<i32>,
-        user_secure_ids: &[i64],
-    ) -> Vec<KeyParameter> {
-        let mut params = vec![
-            KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
-            KeyParameter::new(
-                KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::Algorithm(Algorithm::RSA),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
-            KeyParameter::new(
-                KeyParameterValue::BlockMode(BlockMode::ECB),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::BlockMode(BlockMode::GCM),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
-            KeyParameter::new(
-                KeyParameterValue::Digest(Digest::MD5),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::Digest(Digest::SHA_2_224),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::Digest(Digest::SHA_2_256),
-                SecurityLevel::STRONGBOX,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::PaddingMode(PaddingMode::NONE),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
-                SecurityLevel::STRONGBOX,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
-            KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
-            KeyParameter::new(
-                KeyParameterValue::EcCurve(EcCurve::P_224),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
-            KeyParameter::new(
-                KeyParameterValue::EcCurve(EcCurve::P_384),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::EcCurve(EcCurve::P_521),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::RSAPublicExponent(3),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::IncludeUniqueID,
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
-            KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
-            KeyParameter::new(
-                KeyParameterValue::ActiveDateTime(1234567890),
-                SecurityLevel::STRONGBOX,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::OriginationExpireDateTime(1234567890),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::UsageExpireDateTime(1234567890),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::MinSecondsBetweenOps(1234567890),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::MaxUsesPerBoot(1234567890),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
-            KeyParameter::new(
-                KeyParameterValue::NoAuthRequired,
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
-            KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
-            KeyParameter::new(
-                KeyParameterValue::TrustedUserPresenceRequired,
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::TrustedConfirmationRequired,
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::UnlockedDeviceRequired,
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
-                SecurityLevel::SOFTWARE,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
-                SecurityLevel::SOFTWARE,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::CreationDateTime(12345677890),
-                SecurityLevel::SOFTWARE,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
-            KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
-            KeyParameter::new(
-                KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
-                SecurityLevel::SOFTWARE,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::AttestationIdSecondIMEI(vec![4u8, 3u8, 1u8, 2u8]),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::VendorPatchLevel(3),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::BootPatchLevel(4),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::MacLength(256),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::ResetSinceIdRotation,
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-            KeyParameter::new(
-                KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ),
-        ];
-        if let Some(value) = max_usage_count {
-            params.push(KeyParameter::new(
-                KeyParameterValue::UsageCountLimit(value),
-                SecurityLevel::SOFTWARE,
-            ));
-        }
-
-        for sid in user_secure_ids.iter() {
-            params.push(KeyParameter::new(
-                KeyParameterValue::UserSecureID(*sid),
-                SecurityLevel::STRONGBOX,
-            ));
-        }
-        params
-    }
-
-    pub fn make_test_key_entry(
-        db: &mut KeystoreDB,
-        domain: Domain,
-        namespace: i64,
-        alias: &str,
-        max_usage_count: Option<i32>,
-    ) -> Result<KeyIdGuard> {
-        make_test_key_entry_with_sids(db, domain, namespace, alias, max_usage_count, &[42])
-    }
-
-    pub fn make_test_key_entry_with_sids(
-        db: &mut KeystoreDB,
-        domain: Domain,
-        namespace: i64,
-        alias: &str,
-        max_usage_count: Option<i32>,
-        sids: &[i64],
-    ) -> Result<KeyIdGuard> {
-        let key_id = create_key_entry(db, &domain, &namespace, KeyType::Client, &KEYSTORE_UUID)?;
-        let mut blob_metadata = BlobMetaData::new();
-        blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
-        blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
-        blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
-        blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
-        blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
-
-        db.set_blob(
-            &key_id,
-            SubComponentType::KEY_BLOB,
-            Some(TEST_KEY_BLOB),
-            Some(&blob_metadata),
-        )?;
-        db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
-        db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
-
-        let params = make_test_params_with_sids(max_usage_count, sids);
-        db.insert_keyparameter(&key_id, &params)?;
-
-        let mut metadata = KeyMetaData::new();
-        metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
-        db.insert_key_metadata(&key_id, &metadata)?;
-        rebind_alias(db, &key_id, alias, domain, namespace)?;
-        Ok(key_id)
-    }
-
-    fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
-        let params = make_test_params(max_usage_count);
-
-        let mut blob_metadata = BlobMetaData::new();
-        blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
-        blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
-        blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
-        blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
-        blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
-
-        let mut metadata = KeyMetaData::new();
-        metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
-
-        KeyEntry {
-            id: key_id,
-            key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
-            cert: Some(TEST_CERT_BLOB.to_vec()),
-            cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
-            km_uuid: KEYSTORE_UUID,
-            parameters: params,
-            metadata,
-            pure_cert: false,
-        }
-    }
-
-    pub fn make_bootlevel_key_entry(
-        db: &mut KeystoreDB,
-        domain: Domain,
-        namespace: i64,
-        alias: &str,
-        logical_only: bool,
-    ) -> Result<KeyIdGuard> {
-        let key_id = create_key_entry(db, &domain, &namespace, KeyType::Client, &KEYSTORE_UUID)?;
-        let mut blob_metadata = BlobMetaData::new();
-        if !logical_only {
-            blob_metadata.add(BlobMetaEntry::MaxBootLevel(3));
-        }
-        blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
-
-        db.set_blob(
-            &key_id,
-            SubComponentType::KEY_BLOB,
-            Some(TEST_KEY_BLOB),
-            Some(&blob_metadata),
-        )?;
-        db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
-        db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
-
-        let mut params = make_test_params(None);
-        params.push(KeyParameter::new(KeyParameterValue::MaxBootLevel(3), SecurityLevel::KEYSTORE));
-
-        db.insert_keyparameter(&key_id, &params)?;
-
-        let mut metadata = KeyMetaData::new();
-        metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
-        db.insert_key_metadata(&key_id, &metadata)?;
-        rebind_alias(db, &key_id, alias, domain, namespace)?;
-        Ok(key_id)
-    }
-
-    // Creates an app key that is marked as being superencrypted by the given
-    // super key ID and that has the given authentication and unlocked device
-    // parameters. This does not actually superencrypt the key blob.
-    fn make_superencrypted_key_entry(
-        db: &mut KeystoreDB,
-        namespace: i64,
-        alias: &str,
-        requires_authentication: bool,
-        requires_unlocked_device: bool,
-        super_key_id: i64,
-    ) -> Result<KeyIdGuard> {
-        let domain = Domain::APP;
-        let key_id = create_key_entry(db, &domain, &namespace, KeyType::Client, &KEYSTORE_UUID)?;
-
-        let mut blob_metadata = BlobMetaData::new();
-        blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
-        blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::KeyId(super_key_id)));
-        db.set_blob(
-            &key_id,
-            SubComponentType::KEY_BLOB,
-            Some(TEST_KEY_BLOB),
-            Some(&blob_metadata),
-        )?;
-
-        let mut params = vec![];
-        if requires_unlocked_device {
-            params.push(KeyParameter::new(
-                KeyParameterValue::UnlockedDeviceRequired,
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ));
-        }
-        if requires_authentication {
-            params.push(KeyParameter::new(
-                KeyParameterValue::UserSecureID(42),
-                SecurityLevel::TRUSTED_ENVIRONMENT,
-            ));
-        }
-        db.insert_keyparameter(&key_id, &params)?;
-
-        let mut metadata = KeyMetaData::new();
-        metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
-        db.insert_key_metadata(&key_id, &metadata)?;
-
-        rebind_alias(db, &key_id, alias, domain, namespace)?;
-        Ok(key_id)
-    }
-
-    fn make_bootlevel_test_key_entry_test_vector(key_id: i64, logical_only: bool) -> KeyEntry {
-        let mut params = make_test_params(None);
-        params.push(KeyParameter::new(KeyParameterValue::MaxBootLevel(3), SecurityLevel::KEYSTORE));
-
-        let mut blob_metadata = BlobMetaData::new();
-        if !logical_only {
-            blob_metadata.add(BlobMetaEntry::MaxBootLevel(3));
-        }
-        blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
-
-        let mut metadata = KeyMetaData::new();
-        metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
-
-        KeyEntry {
-            id: key_id,
-            key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
-            cert: Some(TEST_CERT_BLOB.to_vec()),
-            cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
-            km_uuid: KEYSTORE_UUID,
-            parameters: params,
-            metadata,
-            pure_cert: false,
-        }
-    }
-
-    fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
-        let mut stmt = db.conn.prepare(
-            "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
-        )?;
-        let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
-            [],
-            |row| {
-                Ok((
-                    row.get(0)?,
-                    row.get(1)?,
-                    row.get(2)?,
-                    row.get(3)?,
-                    row.get(4)?,
-                    row.get(5)?,
-                    row.get(6)?,
-                ))
-            },
-        )?;
-
-        println!("Key entry table rows:");
-        for r in rows {
-            let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
-            println!(
-                "    id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
-                id, key_type, domain, namespace, alias, state, km_uuid
-            );
-        }
-        Ok(())
-    }
-
-    fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
-        let mut stmt = db
-            .conn
-            .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
-        let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>([], |row| {
-            Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
-        })?;
-
-        println!("Grant table rows:");
-        for r in rows {
-            let (id, gt, ki, av) = r.unwrap();
-            println!("    id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
-        }
-        Ok(())
-    }
-
-    // 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> = const { RefCell::new(0) };
-    }
-
-    fn reset_random() {
-        RANDOM_COUNTER.with(|counter| {
-            *counter.borrow_mut() = 0;
-        })
-    }
-
-    pub fn random() -> i64 {
-        RANDOM_COUNTER.with(|counter| {
-            let result = *counter.borrow() / 2;
-            *counter.borrow_mut() += 1;
-            result
-        })
-    }
-
-    #[test]
-    fn test_unbind_keys_for_user() -> Result<()> {
-        let mut db = new_test_db()?;
-        db.unbind_keys_for_user(1)?;
-
-        make_test_key_entry(&mut db, Domain::APP, 210000, TEST_ALIAS, None)?;
-        make_test_key_entry(&mut db, Domain::APP, 110000, TEST_ALIAS, None)?;
-        db.unbind_keys_for_user(2)?;
-
-        assert_eq!(1, db.list_past_alias(Domain::APP, 110000, KeyType::Client, None)?.len());
-        assert_eq!(0, db.list_past_alias(Domain::APP, 210000, KeyType::Client, None)?.len());
-
-        db.unbind_keys_for_user(1)?;
-        assert_eq!(0, db.list_past_alias(Domain::APP, 110000, KeyType::Client, None)?.len());
-
-        Ok(())
-    }
-
-    #[test]
-    fn test_unbind_keys_for_user_removes_superkeys() -> Result<()> {
-        let mut db = new_test_db()?;
-        let super_key = keystore2_crypto::generate_aes256_key()?;
-        let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
-        let (encrypted_super_key, metadata) =
-            SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
-
-        let key_name_enc = SuperKeyType {
-            alias: "test_super_key_1",
-            algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
-            name: "test_super_key_1",
-        };
-
-        let key_name_nonenc = SuperKeyType {
-            alias: "test_super_key_2",
-            algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
-            name: "test_super_key_2",
-        };
-
-        // Install two super keys.
-        db.store_super_key(
-            1,
-            &key_name_nonenc,
-            &super_key,
-            &BlobMetaData::new(),
-            &KeyMetaData::new(),
-        )?;
-        db.store_super_key(1, &key_name_enc, &encrypted_super_key, &metadata, &KeyMetaData::new())?;
-
-        // Check that both can be found in the database.
-        assert!(db.load_super_key(&key_name_enc, 1)?.is_some());
-        assert!(db.load_super_key(&key_name_nonenc, 1)?.is_some());
-
-        // Install the same keys for a different user.
-        db.store_super_key(
-            2,
-            &key_name_nonenc,
-            &super_key,
-            &BlobMetaData::new(),
-            &KeyMetaData::new(),
-        )?;
-        db.store_super_key(2, &key_name_enc, &encrypted_super_key, &metadata, &KeyMetaData::new())?;
-
-        // Check that the second pair of keys can be found in the database.
-        assert!(db.load_super_key(&key_name_enc, 2)?.is_some());
-        assert!(db.load_super_key(&key_name_nonenc, 2)?.is_some());
-
-        // Delete all keys for user 1.
-        db.unbind_keys_for_user(1)?;
-
-        // All of user 1's keys should be gone.
-        assert!(db.load_super_key(&key_name_enc, 1)?.is_none());
-        assert!(db.load_super_key(&key_name_nonenc, 1)?.is_none());
-
-        // User 2's keys should not have been touched.
-        assert!(db.load_super_key(&key_name_enc, 2)?.is_some());
-        assert!(db.load_super_key(&key_name_nonenc, 2)?.is_some());
-
-        Ok(())
-    }
-
-    fn app_key_exists(db: &mut KeystoreDB, nspace: i64, alias: &str) -> Result<bool> {
-        db.key_exists(Domain::APP, nspace, alias, KeyType::Client)
-    }
-
-    // Tests the unbind_auth_bound_keys_for_user() function.
-    #[test]
-    fn test_unbind_auth_bound_keys_for_user() -> Result<()> {
-        let mut db = new_test_db()?;
-        let user_id = 1;
-        let nspace: i64 = (user_id * AID_USER_OFFSET).into();
-        let other_user_id = 2;
-        let other_user_nspace: i64 = (other_user_id * AID_USER_OFFSET).into();
-        let super_key_type = &USER_AFTER_FIRST_UNLOCK_SUPER_KEY;
-
-        // Create a superencryption key.
-        let super_key = keystore2_crypto::generate_aes256_key()?;
-        let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
-        let (encrypted_super_key, blob_metadata) =
-            SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
-        db.store_super_key(
-            user_id,
-            super_key_type,
-            &encrypted_super_key,
-            &blob_metadata,
-            &KeyMetaData::new(),
-        )?;
-        let super_key_id = db.load_super_key(super_key_type, user_id)?.unwrap().0 .0;
-
-        // Store 4 superencrypted app keys, one for each possible combination of
-        // (authentication required, unlocked device required).
-        make_superencrypted_key_entry(&mut db, nspace, "noauth_noud", false, false, super_key_id)?;
-        make_superencrypted_key_entry(&mut db, nspace, "noauth_ud", false, true, super_key_id)?;
-        make_superencrypted_key_entry(&mut db, nspace, "auth_noud", true, false, super_key_id)?;
-        make_superencrypted_key_entry(&mut db, nspace, "auth_ud", true, true, super_key_id)?;
-        assert!(app_key_exists(&mut db, nspace, "noauth_noud")?);
-        assert!(app_key_exists(&mut db, nspace, "noauth_ud")?);
-        assert!(app_key_exists(&mut db, nspace, "auth_noud")?);
-        assert!(app_key_exists(&mut db, nspace, "auth_ud")?);
-
-        // Also store a key for a different user that requires authentication.
-        make_superencrypted_key_entry(
-            &mut db,
-            other_user_nspace,
-            "auth_ud",
-            true,
-            true,
-            super_key_id,
-        )?;
-
-        db.unbind_auth_bound_keys_for_user(user_id)?;
-
-        // Verify that only the user's app keys that require authentication were
-        // deleted. Keys that require an unlocked device but not authentication
-        // should *not* have been deleted, nor should the super key have been
-        // deleted, nor should other users' keys have been deleted.
-        assert!(db.load_super_key(super_key_type, user_id)?.is_some());
-        assert!(app_key_exists(&mut db, nspace, "noauth_noud")?);
-        assert!(app_key_exists(&mut db, nspace, "noauth_ud")?);
-        assert!(!app_key_exists(&mut db, nspace, "auth_noud")?);
-        assert!(!app_key_exists(&mut db, nspace, "auth_ud")?);
-        assert!(app_key_exists(&mut db, other_user_nspace, "auth_ud")?);
-
-        Ok(())
-    }
-
-    #[test]
-    fn test_store_super_key() -> Result<()> {
-        let mut db = new_test_db()?;
-        let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
-        let super_key = keystore2_crypto::generate_aes256_key()?;
-        let secret_bytes = b"keystore2 is great.";
-        let (encrypted_secret, iv, tag) =
-            keystore2_crypto::aes_gcm_encrypt(secret_bytes, &super_key)?;
-
-        let (encrypted_super_key, metadata) =
-            SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
-        db.store_super_key(
-            1,
-            &USER_AFTER_FIRST_UNLOCK_SUPER_KEY,
-            &encrypted_super_key,
-            &metadata,
-            &KeyMetaData::new(),
-        )?;
-
-        // Check if super key exists.
-        assert!(db.key_exists(
-            Domain::APP,
-            1,
-            USER_AFTER_FIRST_UNLOCK_SUPER_KEY.alias,
-            KeyType::Super
-        )?);
-
-        let (_, key_entry) = db.load_super_key(&USER_AFTER_FIRST_UNLOCK_SUPER_KEY, 1)?.unwrap();
-        let loaded_super_key = SuperKeyManager::extract_super_key_from_key_entry(
-            USER_AFTER_FIRST_UNLOCK_SUPER_KEY.algorithm,
-            key_entry,
-            &pw,
-            None,
-        )?;
-
-        let decrypted_secret_bytes = loaded_super_key.decrypt(&encrypted_secret, &iv, &tag)?;
-        assert_eq!(secret_bytes, &*decrypted_secret_bytes);
-
-        Ok(())
-    }
-
-    fn get_valid_statsd_storage_types() -> Vec<MetricsStorage> {
-        vec![
-            MetricsStorage::KEY_ENTRY,
-            MetricsStorage::KEY_ENTRY_ID_INDEX,
-            MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX,
-            MetricsStorage::BLOB_ENTRY,
-            MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX,
-            MetricsStorage::KEY_PARAMETER,
-            MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX,
-            MetricsStorage::KEY_METADATA,
-            MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX,
-            MetricsStorage::GRANT,
-            MetricsStorage::AUTH_TOKEN,
-            MetricsStorage::BLOB_METADATA,
-            MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX,
-        ]
-    }
-
-    /// Perform a simple check to ensure that we can query all the storage types
-    /// that are supported by the DB. Check for reasonable values.
-    #[test]
-    fn test_query_all_valid_table_sizes() -> Result<()> {
-        const PAGE_SIZE: i32 = 4096;
-
-        let mut db = new_test_db()?;
-
-        for t in get_valid_statsd_storage_types() {
-            let stat = db.get_storage_stat(t)?;
-            // AuthToken can be less than a page since it's in a btree, not sqlite
-            // TODO(b/187474736) stop using if-let here
-            if let MetricsStorage::AUTH_TOKEN = t {
-            } else {
-                assert!(stat.size >= PAGE_SIZE);
-            }
-            assert!(stat.size >= stat.unused_size);
-        }
-
-        Ok(())
-    }
-
-    fn get_storage_stats_map(db: &mut KeystoreDB) -> BTreeMap<i32, StorageStats> {
-        get_valid_statsd_storage_types()
-            .into_iter()
-            .map(|t| (t.0, db.get_storage_stat(t).unwrap()))
-            .collect()
-    }
-
-    fn assert_storage_increased(
-        db: &mut KeystoreDB,
-        increased_storage_types: Vec<MetricsStorage>,
-        baseline: &mut BTreeMap<i32, StorageStats>,
-    ) {
-        for storage in increased_storage_types {
-            // Verify the expected storage increased.
-            let new = db.get_storage_stat(storage).unwrap();
-            let old = &baseline[&storage.0];
-            assert!(new.size >= old.size, "{}: {} >= {}", storage.0, new.size, old.size);
-            assert!(
-                new.unused_size <= old.unused_size,
-                "{}: {} <= {}",
-                storage.0,
-                new.unused_size,
-                old.unused_size
-            );
-
-            // Update the baseline with the new value so that it succeeds in the
-            // later comparison.
-            baseline.insert(storage.0, new);
-        }
-
-        // Get an updated map of the storage and verify there were no unexpected changes.
-        let updated_stats = get_storage_stats_map(db);
-        assert_eq!(updated_stats.len(), baseline.len());
-
-        for &k in baseline.keys() {
-            let stringify = |map: &BTreeMap<i32, StorageStats>| -> String {
-                let mut s = String::new();
-                for &k in map.keys() {
-                    writeln!(&mut s, "  {}: {}, {}", &k, map[&k].size, map[&k].unused_size)
-                        .expect("string concat failed");
-                }
-                s
-            };
-
-            assert!(
-                updated_stats[&k].size == baseline[&k].size
-                    && updated_stats[&k].unused_size == baseline[&k].unused_size,
-                "updated_stats:\n{}\nbaseline:\n{}",
-                stringify(&updated_stats),
-                stringify(baseline)
-            );
-        }
-    }
-
-    #[test]
-    fn test_verify_key_table_size_reporting() -> Result<()> {
-        let mut db = new_test_db()?;
-        let mut working_stats = get_storage_stats_map(&mut db);
-
-        let key_id = create_key_entry(&mut db, &Domain::APP, &42, KeyType::Client, &KEYSTORE_UUID)?;
-        assert_storage_increased(
-            &mut db,
-            vec![
-                MetricsStorage::KEY_ENTRY,
-                MetricsStorage::KEY_ENTRY_ID_INDEX,
-                MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX,
-            ],
-            &mut working_stats,
-        );
-
-        let mut blob_metadata = BlobMetaData::new();
-        blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
-        db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB), None)?;
-        assert_storage_increased(
-            &mut db,
-            vec![
-                MetricsStorage::BLOB_ENTRY,
-                MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX,
-                MetricsStorage::BLOB_METADATA,
-                MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX,
-            ],
-            &mut working_stats,
-        );
-
-        let params = make_test_params(None);
-        db.insert_keyparameter(&key_id, &params)?;
-        assert_storage_increased(
-            &mut db,
-            vec![MetricsStorage::KEY_PARAMETER, MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX],
-            &mut working_stats,
-        );
-
-        let mut metadata = KeyMetaData::new();
-        metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
-        db.insert_key_metadata(&key_id, &metadata)?;
-        assert_storage_increased(
-            &mut db,
-            vec![MetricsStorage::KEY_METADATA, MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX],
-            &mut working_stats,
-        );
-
-        let mut sum = 0;
-        for stat in working_stats.values() {
-            sum += stat.size;
-        }
-        let total = db.get_storage_stat(MetricsStorage::DATABASE)?.size;
-        assert!(sum <= total, "Expected sum <= total. sum: {}, total: {}", sum, total);
-
-        Ok(())
-    }
-
-    #[test]
-    fn test_verify_auth_table_size_reporting() -> Result<()> {
-        let mut db = new_test_db()?;
-        let mut working_stats = get_storage_stats_map(&mut db);
-        db.insert_auth_token(&HardwareAuthToken {
-            challenge: 123,
-            userId: 456,
-            authenticatorId: 789,
-            authenticatorType: kmhw_authenticator_type::ANY,
-            timestamp: Timestamp { milliSeconds: 10 },
-            mac: b"mac".to_vec(),
-        });
-        assert_storage_increased(&mut db, vec![MetricsStorage::AUTH_TOKEN], &mut working_stats);
-        Ok(())
-    }
-
-    #[test]
-    fn test_verify_grant_table_size_reporting() -> Result<()> {
-        const OWNER: i64 = 1;
-        let mut db = new_test_db()?;
-        make_test_key_entry(&mut db, Domain::APP, OWNER, TEST_ALIAS, None)?;
-
-        let mut working_stats = get_storage_stats_map(&mut db);
-        db.grant(
-            &KeyDescriptor {
-                domain: Domain::APP,
-                nspace: 0,
-                alias: Some(TEST_ALIAS.to_string()),
-                blob: None,
-            },
-            OWNER as u32,
-            123,
-            key_perm_set![KeyPerm::Use],
-            |_, _| Ok(()),
-        )?;
-
-        assert_storage_increased(&mut db, vec![MetricsStorage::GRANT], &mut working_stats);
-
-        Ok(())
-    }
-
-    #[test]
-    fn find_auth_token_entry_returns_latest() -> Result<()> {
-        let mut db = new_test_db()?;
-        db.insert_auth_token(&HardwareAuthToken {
-            challenge: 123,
-            userId: 456,
-            authenticatorId: 789,
-            authenticatorType: kmhw_authenticator_type::ANY,
-            timestamp: Timestamp { milliSeconds: 10 },
-            mac: b"mac0".to_vec(),
-        });
-        std::thread::sleep(std::time::Duration::from_millis(1));
-        db.insert_auth_token(&HardwareAuthToken {
-            challenge: 123,
-            userId: 457,
-            authenticatorId: 789,
-            authenticatorType: kmhw_authenticator_type::ANY,
-            timestamp: Timestamp { milliSeconds: 12 },
-            mac: b"mac1".to_vec(),
-        });
-        std::thread::sleep(std::time::Duration::from_millis(1));
-        db.insert_auth_token(&HardwareAuthToken {
-            challenge: 123,
-            userId: 458,
-            authenticatorId: 789,
-            authenticatorType: kmhw_authenticator_type::ANY,
-            timestamp: Timestamp { milliSeconds: 3 },
-            mac: b"mac2".to_vec(),
-        });
-        // All three entries are in the database
-        assert_eq!(db.perboot.auth_tokens_len(), 3);
-        // It selected the most recent timestamp
-        assert_eq!(db.find_auth_token_entry(|_| true).unwrap().auth_token.mac, b"mac2".to_vec());
-        Ok(())
-    }
-
-    #[test]
-    fn test_load_key_descriptor() -> Result<()> {
-        let mut db = new_test_db()?;
-        let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)?.0;
-
-        let key = db.load_key_descriptor(key_id)?.unwrap();
-
-        assert_eq!(key.domain, Domain::APP);
-        assert_eq!(key.nspace, 1);
-        assert_eq!(key.alias, Some(TEST_ALIAS.to_string()));
-
-        // No such id
-        assert_eq!(db.load_key_descriptor(key_id + 1)?, None);
-        Ok(())
-    }
-
-    #[test]
-    fn test_get_list_app_uids_for_sid() -> Result<()> {
-        let uid: i32 = 1;
-        let uid_offset: i64 = (uid as i64) * (AID_USER_OFFSET as i64);
-        let first_sid = 667;
-        let second_sid = 669;
-        let first_app_id: i64 = 123 + uid_offset;
-        let second_app_id: i64 = 456 + uid_offset;
-        let third_app_id: i64 = 789 + uid_offset;
-        let unrelated_app_id: i64 = 1011 + uid_offset;
-        let mut db = new_test_db()?;
-        make_test_key_entry_with_sids(
-            &mut db,
-            Domain::APP,
-            first_app_id,
-            TEST_ALIAS,
-            None,
-            &[first_sid],
-        )
-        .context("test_get_list_app_uids_for_sid")?;
-        make_test_key_entry_with_sids(
-            &mut db,
-            Domain::APP,
-            second_app_id,
-            "alias2",
-            None,
-            &[first_sid],
-        )
-        .context("test_get_list_app_uids_for_sid")?;
-        make_test_key_entry_with_sids(
-            &mut db,
-            Domain::APP,
-            second_app_id,
-            TEST_ALIAS,
-            None,
-            &[second_sid],
-        )
-        .context("test_get_list_app_uids_for_sid")?;
-        make_test_key_entry_with_sids(
-            &mut db,
-            Domain::APP,
-            third_app_id,
-            "alias3",
-            None,
-            &[second_sid],
-        )
-        .context("test_get_list_app_uids_for_sid")?;
-        make_test_key_entry_with_sids(
-            &mut db,
-            Domain::APP,
-            unrelated_app_id,
-            TEST_ALIAS,
-            None,
-            &[],
-        )
-        .context("test_get_list_app_uids_for_sid")?;
-
-        let mut first_sid_apps = db.get_app_uids_affected_by_sid(uid, first_sid)?;
-        first_sid_apps.sort();
-        assert_eq!(first_sid_apps, vec![first_app_id, second_app_id]);
-        let mut second_sid_apps = db.get_app_uids_affected_by_sid(uid, second_sid)?;
-        second_sid_apps.sort();
-        assert_eq!(second_sid_apps, vec![second_app_id, third_app_id]);
-        Ok(())
-    }
-
-    #[test]
-    fn test_get_list_app_uids_with_multiple_sids() -> Result<()> {
-        let uid: i32 = 1;
-        let uid_offset: i64 = (uid as i64) * (AID_USER_OFFSET as i64);
-        let first_sid = 667;
-        let second_sid = 669;
-        let third_sid = 772;
-        let first_app_id: i64 = 123 + uid_offset;
-        let second_app_id: i64 = 456 + uid_offset;
-        let mut db = new_test_db()?;
-        make_test_key_entry_with_sids(
-            &mut db,
-            Domain::APP,
-            first_app_id,
-            TEST_ALIAS,
-            None,
-            &[first_sid, second_sid],
-        )
-        .context("test_get_list_app_uids_for_sid")?;
-        make_test_key_entry_with_sids(
-            &mut db,
-            Domain::APP,
-            second_app_id,
-            "alias2",
-            None,
-            &[second_sid, third_sid],
-        )
-        .context("test_get_list_app_uids_for_sid")?;
-
-        let first_sid_apps = db.get_app_uids_affected_by_sid(uid, first_sid)?;
-        assert_eq!(first_sid_apps, vec![first_app_id]);
-
-        let mut second_sid_apps = db.get_app_uids_affected_by_sid(uid, second_sid)?;
-        second_sid_apps.sort();
-        assert_eq!(second_sid_apps, vec![first_app_id, second_app_id]);
-
-        let third_sid_apps = db.get_app_uids_affected_by_sid(uid, third_sid)?;
-        assert_eq!(third_sid_apps, vec![second_app_id]);
-        Ok(())
-    }
-}
diff --git a/keystore2/src/database/tests.rs b/keystore2/src/database/tests.rs
new file mode 100644
index 0000000..031d749
--- /dev/null
+++ b/keystore2/src/database/tests.rs
@@ -0,0 +1,2528 @@
+// 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.
+
+//! Database tests.
+
+use super::*;
+use crate::key_parameter::{
+    Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
+    KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
+};
+use crate::key_perm_set;
+use crate::permission::{KeyPerm, KeyPermSet};
+use crate::super_key::{SuperKeyManager, USER_AFTER_FIRST_UNLOCK_SUPER_KEY, SuperEncryptionAlgorithm, SuperKeyType};
+use keystore2_test_utils::TempDir;
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+    HardwareAuthToken::HardwareAuthToken,
+    HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
+};
+use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
+    Timestamp::Timestamp,
+};
+use std::cell::RefCell;
+use std::collections::BTreeMap;
+use std::fmt::Write;
+use std::sync::atomic::{AtomicU8, Ordering};
+use std::sync::Arc;
+use std::thread;
+use std::time::{Duration, SystemTime};
+use crate::utils::AesGcm;
+#[cfg(disabled)]
+use std::time::Instant;
+
+pub fn new_test_db() -> Result<KeystoreDB> {
+    let conn = KeystoreDB::make_connection("file::memory:")?;
+
+    let mut db = KeystoreDB { conn, gc: None, perboot: Arc::new(perboot::PerbootDB::new()) };
+    db.with_transaction(Immediate("TX_new_test_db"), |tx| {
+        KeystoreDB::init_tables(tx).context("Failed to initialize tables.").no_gc()
+    })?;
+    Ok(db)
+}
+
+fn rebind_alias(
+    db: &mut KeystoreDB,
+    newid: &KeyIdGuard,
+    alias: &str,
+    domain: Domain,
+    namespace: i64,
+) -> Result<bool> {
+    db.with_transaction(Immediate("TX_rebind_alias"), |tx| {
+        KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace, KeyType::Client).no_gc()
+    })
+    .context(ks_err!())
+}
+
+#[test]
+fn datetime() -> Result<()> {
+    let conn = Connection::open_in_memory()?;
+    conn.execute("CREATE TABLE test (ts DATETIME);", [])?;
+    let now = SystemTime::now();
+    let duration = Duration::from_secs(1000);
+    let then = now.checked_sub(duration).unwrap();
+    let soon = now.checked_add(duration).unwrap();
+    conn.execute(
+        "INSERT INTO test (ts) VALUES (?), (?), (?);",
+        params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
+    )?;
+    let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
+    let mut rows = stmt.query([])?;
+    assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
+    assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
+    assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
+    assert!(rows.next()?.is_none());
+    assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
+    assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
+    assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
+    Ok(())
+}
+
+// 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);
+    }
+}
+
+// Test that we have the correct tables.
+#[test]
+fn test_tables() -> Result<()> {
+    let db = new_test_db()?;
+    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(), 6);
+    assert_eq!(tables[0], "blobentry");
+    assert_eq!(tables[1], "blobmetadata");
+    assert_eq!(tables[2], "grant");
+    assert_eq!(tables[3], "keyentry");
+    assert_eq!(tables[4], "keymetadata");
+    assert_eq!(tables[5], "keyparameter");
+    Ok(())
+}
+
+#[test]
+fn test_auth_token_table_invariant() -> Result<()> {
+    let mut db = new_test_db()?;
+    let auth_token1 = HardwareAuthToken {
+        challenge: i64::MAX,
+        userId: 200,
+        authenticatorId: 200,
+        authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
+        timestamp: Timestamp { milliSeconds: 500 },
+        mac: String::from("mac").into_bytes(),
+    };
+    db.insert_auth_token(&auth_token1);
+    let auth_tokens_returned = get_auth_tokens(&db);
+    assert_eq!(auth_tokens_returned.len(), 1);
+
+    // insert another auth token with the same values for the columns in the UNIQUE constraint
+    // of the auth token table and different value for timestamp
+    let auth_token2 = HardwareAuthToken {
+        challenge: i64::MAX,
+        userId: 200,
+        authenticatorId: 200,
+        authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
+        timestamp: Timestamp { milliSeconds: 600 },
+        mac: String::from("mac").into_bytes(),
+    };
+
+    db.insert_auth_token(&auth_token2);
+    let mut auth_tokens_returned = get_auth_tokens(&db);
+    assert_eq!(auth_tokens_returned.len(), 1);
+
+    if let Some(auth_token) = auth_tokens_returned.pop() {
+        assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
+    }
+
+    // insert another auth token with the different values for the columns in the UNIQUE
+    // constraint of the auth token table
+    let auth_token3 = HardwareAuthToken {
+        challenge: i64::MAX,
+        userId: 201,
+        authenticatorId: 200,
+        authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
+        timestamp: Timestamp { milliSeconds: 600 },
+        mac: String::from("mac").into_bytes(),
+    };
+
+    db.insert_auth_token(&auth_token3);
+    let auth_tokens_returned = get_auth_tokens(&db);
+    assert_eq!(auth_tokens_returned.len(), 2);
+
+    Ok(())
+}
+
+// utility function for test_auth_token_table_invariant()
+fn get_auth_tokens(db: &KeystoreDB) -> Vec<AuthTokenEntry> {
+    db.perboot.get_all_auth_token_entries()
+}
+
+fn create_key_entry(
+    db: &mut KeystoreDB,
+    domain: &Domain,
+    namespace: &i64,
+    key_type: KeyType,
+    km_uuid: &Uuid,
+) -> Result<KeyIdGuard> {
+    db.with_transaction(Immediate("TX_create_key_entry"), |tx| {
+        KeystoreDB::create_key_entry_internal(tx, domain, namespace, key_type, km_uuid).no_gc()
+    })
+}
+
+#[test]
+fn test_persistence_for_files() -> Result<()> {
+    let temp_dir = TempDir::new("persistent_db_test")?;
+    let mut db = KeystoreDB::new(temp_dir.path(), None)?;
+
+    create_key_entry(&mut db, &Domain::APP, &100, KeyType::Client, &KEYSTORE_UUID)?;
+    let entries = get_keyentry(&db)?;
+    assert_eq!(entries.len(), 1);
+
+    let db = KeystoreDB::new(temp_dir.path(), None)?;
+
+    let entries_new = get_keyentry(&db)?;
+    assert_eq!(entries, entries_new);
+    Ok(())
+}
+
+#[test]
+fn test_create_key_entry() -> Result<()> {
+    fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
+        (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
+    }
+
+    let mut db = new_test_db()?;
+
+    create_key_entry(&mut db, &Domain::APP, &100, KeyType::Client, &KEYSTORE_UUID)?;
+    create_key_entry(&mut db, &Domain::SELINUX, &101, KeyType::Client, &KEYSTORE_UUID)?;
+
+    let entries = get_keyentry(&db)?;
+    assert_eq!(entries.len(), 2);
+    assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
+    assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
+
+    // Test that we must pass in a valid Domain.
+    check_result_is_error_containing_string(
+        create_key_entry(&mut db, &Domain::GRANT, &102, KeyType::Client, &KEYSTORE_UUID),
+        &format!("Domain {:?} must be either App or SELinux.", Domain::GRANT),
+    );
+    check_result_is_error_containing_string(
+        create_key_entry(&mut db, &Domain::BLOB, &103, KeyType::Client, &KEYSTORE_UUID),
+        &format!("Domain {:?} must be either App or SELinux.", Domain::BLOB),
+    );
+    check_result_is_error_containing_string(
+        create_key_entry(&mut db, &Domain::KEY_ID, &104, KeyType::Client, &KEYSTORE_UUID),
+        &format!("Domain {:?} must be either App or SELinux.", Domain::KEY_ID),
+    );
+
+    Ok(())
+}
+
+#[test]
+fn test_rebind_alias() -> Result<()> {
+    fn extractor(ke: &KeyEntryRow) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
+        (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
+    }
+
+    let mut db = new_test_db()?;
+    create_key_entry(&mut db, &Domain::APP, &42, KeyType::Client, &KEYSTORE_UUID)?;
+    create_key_entry(&mut db, &Domain::APP, &42, KeyType::Client, &KEYSTORE_UUID)?;
+    let entries = get_keyentry(&db)?;
+    assert_eq!(entries.len(), 2);
+    assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID)));
+    assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID)));
+
+    // Test that the first call to rebind_alias sets the alias.
+    rebind_alias(&mut db, &KEY_ID_LOCK.get(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"), Some(KEYSTORE_UUID))
+    );
+    assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID)));
+
+    // Test that the second call to rebind_alias also empties the old one.
+    rebind_alias(&mut db, &KEY_ID_LOCK.get(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, Some(KEYSTORE_UUID)));
+    assert_eq!(
+        extractor(&entries[1]),
+        (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
+    );
+
+    // Test that we must pass in a valid Domain.
+    check_result_is_error_containing_string(
+        rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
+        &format!("Domain {:?} must be either App or SELinux.", Domain::GRANT),
+    );
+    check_result_is_error_containing_string(
+        rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
+        &format!("Domain {:?} must be either App or SELinux.", Domain::BLOB),
+    );
+    check_result_is_error_containing_string(
+        rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
+        &format!("Domain {:?} must be either App or SELinux.", Domain::KEY_ID),
+    );
+
+    // Test that we correctly handle setting an alias for something that does not exist.
+    check_result_is_error_containing_string(
+        rebind_alias(&mut db, &KEY_ID_LOCK.get(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, Some(KEYSTORE_UUID)));
+    assert_eq!(
+        extractor(&entries[1]),
+        (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
+    );
+
+    Ok(())
+}
+
+#[test]
+fn test_grant_ungrant() -> Result<()> {
+    const CALLER_UID: u32 = 15;
+    const GRANTEE_UID: u32 = 12;
+    const SELINUX_NAMESPACE: i64 = 7;
+
+    let mut db = new_test_db()?;
+    db.conn.execute(
+        "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
+                VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
+        params![KEYSTORE_UUID, KEYSTORE_UUID],
+    )?;
+    let app_key = KeyDescriptor {
+        domain: super::Domain::APP,
+        nspace: 0,
+        alias: Some("key".to_string()),
+        blob: None,
+    };
+    const PVEC1: KeyPermSet = key_perm_set![KeyPerm::Use, KeyPerm::GetInfo];
+    const PVEC2: KeyPermSet = key_perm_set![KeyPerm::Use];
+
+    // Reset totally predictable random number generator in case we
+    // are not the first test running on this thread.
+    reset_random();
+    let next_random = 0i64;
+
+    let app_granted_key = db
+        .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
+            assert_eq!(*a, PVEC1);
+            assert_eq!(
+                *k,
+                KeyDescriptor {
+                    domain: super::Domain::APP,
+                    // namespace must be set to the caller_uid.
+                    nspace: CALLER_UID as i64,
+                    alias: Some("key".to_string()),
+                    blob: None,
+                }
+            );
+            Ok(())
+        })
+        .unwrap();
+
+    assert_eq!(
+        app_granted_key,
+        KeyDescriptor {
+            domain: super::Domain::GRANT,
+            // The grantid is next_random due to the mock random number generator.
+            nspace: next_random,
+            alias: None,
+            blob: None,
+        }
+    );
+
+    let selinux_key = KeyDescriptor {
+        domain: super::Domain::SELINUX,
+        nspace: SELINUX_NAMESPACE,
+        alias: Some("yek".to_string()),
+        blob: None,
+    };
+
+    let selinux_granted_key = db
+        .grant(&selinux_key, CALLER_UID, 12, PVEC1, |k, a| {
+            assert_eq!(*a, PVEC1);
+            assert_eq!(
+                *k,
+                KeyDescriptor {
+                    domain: super::Domain::SELINUX,
+                    // namespace must be the supplied SELinux
+                    // namespace.
+                    nspace: SELINUX_NAMESPACE,
+                    alias: Some("yek".to_string()),
+                    blob: None,
+                }
+            );
+            Ok(())
+        })
+        .unwrap();
+
+    assert_eq!(
+        selinux_granted_key,
+        KeyDescriptor {
+            domain: super::Domain::GRANT,
+            // The grantid is next_random + 1 due to the mock random number generator.
+            nspace: next_random + 1,
+            alias: None,
+            blob: None,
+        }
+    );
+
+    // This should update the existing grant with PVEC2.
+    let selinux_granted_key = db
+        .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
+            assert_eq!(*a, PVEC2);
+            assert_eq!(
+                *k,
+                KeyDescriptor {
+                    domain: super::Domain::SELINUX,
+                    // namespace must be the supplied SELinux
+                    // namespace.
+                    nspace: SELINUX_NAMESPACE,
+                    alias: Some("yek".to_string()),
+                    blob: None,
+                }
+            );
+            Ok(())
+        })
+        .unwrap();
+
+    assert_eq!(
+        selinux_granted_key,
+        KeyDescriptor {
+            domain: super::Domain::GRANT,
+            // Same grant id as before. The entry was only updated.
+            nspace: next_random + 1,
+            alias: None,
+            blob: None,
+        }
+    );
+
+    {
+        // Limiting scope of stmt, because it borrows db.
+        let mut stmt = db
+            .conn
+            .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
+        let mut rows = stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>([], |row| {
+            Ok((row.get(0)?, row.get(1)?, row.get(2)?, KeyPermSet::from(row.get::<_, i32>(3)?)))
+        })?;
+
+        let r = rows.next().unwrap().unwrap();
+        assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
+        let r = rows.next().unwrap().unwrap();
+        assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
+        assert!(rows.next().is_none());
+    }
+
+    debug_dump_keyentry_table(&mut db)?;
+    println!("app_key {:?}", app_key);
+    println!("selinux_key {:?}", selinux_key);
+
+    db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
+    db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
+
+    Ok(())
+}
+
+static TEST_KEY_BLOB: &[u8] = b"my test blob";
+static TEST_CERT_BLOB: &[u8] = b"my test cert";
+static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
+
+#[test]
+fn test_set_blob() -> Result<()> {
+    let key_id = KEY_ID_LOCK.get(3000);
+    let mut db = new_test_db()?;
+    let mut blob_metadata = BlobMetaData::new();
+    blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
+    db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB), Some(&blob_metadata))?;
+    db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
+    db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
+    drop(key_id);
+
+    let mut stmt = db.conn.prepare(
+        "SELECT subcomponent_type, keyentryid, blob, id FROM persistent.blobentry
+                ORDER BY subcomponent_type ASC;",
+    )?;
+    let mut rows = stmt.query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>([], |row| {
+        Ok(((row.get(0)?, row.get(1)?, row.get(2)?), row.get(3)?))
+    })?;
+    let (r, id) = rows.next().unwrap().unwrap();
+    assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
+    let (r, _) = rows.next().unwrap().unwrap();
+    assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
+    let (r, _) = rows.next().unwrap().unwrap();
+    assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
+
+    drop(rows);
+    drop(stmt);
+
+    assert_eq!(
+        db.with_transaction(Immediate("TX_test"), |tx| {
+            BlobMetaData::load_from_db(id, tx).no_gc()
+        })
+        .expect("Should find blob metadata."),
+        blob_metadata
+    );
+    Ok(())
+}
+
+static TEST_ALIAS: &str = "my super duper key";
+
+#[test]
+fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
+    let mut db = new_test_db()?;
+    let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
+        .context("test_insert_and_load_full_keyentry_domain_app")?
+        .0;
+    let (_key_guard, key_entry) = db
+        .load_key_entry(
+            &KeyDescriptor {
+                domain: Domain::APP,
+                nspace: 0,
+                alias: Some(TEST_ALIAS.to_string()),
+                blob: None,
+            },
+            KeyType::Client,
+            KeyEntryLoadBits::BOTH,
+            1,
+            |_k, _av| Ok(()),
+        )
+        .unwrap();
+    assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
+
+    db.unbind_key(
+        &KeyDescriptor {
+            domain: Domain::APP,
+            nspace: 0,
+            alias: Some(TEST_ALIAS.to_string()),
+            blob: None,
+        },
+        KeyType::Client,
+        1,
+        |_, _| Ok(()),
+    )
+    .unwrap();
+
+    assert_eq!(
+        Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
+        db.load_key_entry(
+            &KeyDescriptor {
+                domain: Domain::APP,
+                nspace: 0,
+                alias: Some(TEST_ALIAS.to_string()),
+                blob: None,
+            },
+            KeyType::Client,
+            KeyEntryLoadBits::NONE,
+            1,
+            |_k, _av| Ok(()),
+        )
+        .unwrap_err()
+        .root_cause()
+        .downcast_ref::<KsError>()
+    );
+
+    Ok(())
+}
+
+#[test]
+fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
+    let mut db = new_test_db()?;
+
+    db.store_new_certificate(
+        &KeyDescriptor {
+            domain: Domain::APP,
+            nspace: 1,
+            alias: Some(TEST_ALIAS.to_string()),
+            blob: None,
+        },
+        KeyType::Client,
+        TEST_CERT_BLOB,
+        &KEYSTORE_UUID,
+    )
+    .expect("Trying to insert cert.");
+
+    let (_key_guard, mut key_entry) = db
+        .load_key_entry(
+            &KeyDescriptor {
+                domain: Domain::APP,
+                nspace: 1,
+                alias: Some(TEST_ALIAS.to_string()),
+                blob: None,
+            },
+            KeyType::Client,
+            KeyEntryLoadBits::PUBLIC,
+            1,
+            |_k, _av| Ok(()),
+        )
+        .expect("Trying to read certificate entry.");
+
+    assert!(key_entry.pure_cert());
+    assert!(key_entry.cert().is_none());
+    assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
+
+    db.unbind_key(
+        &KeyDescriptor {
+            domain: Domain::APP,
+            nspace: 1,
+            alias: Some(TEST_ALIAS.to_string()),
+            blob: None,
+        },
+        KeyType::Client,
+        1,
+        |_, _| Ok(()),
+    )
+    .unwrap();
+
+    assert_eq!(
+        Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
+        db.load_key_entry(
+            &KeyDescriptor {
+                domain: Domain::APP,
+                nspace: 1,
+                alias: Some(TEST_ALIAS.to_string()),
+                blob: None,
+            },
+            KeyType::Client,
+            KeyEntryLoadBits::NONE,
+            1,
+            |_k, _av| Ok(()),
+        )
+        .unwrap_err()
+        .root_cause()
+        .downcast_ref::<KsError>()
+    );
+
+    Ok(())
+}
+
+#[test]
+fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
+    let mut db = new_test_db()?;
+    let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
+        .context("test_insert_and_load_full_keyentry_domain_selinux")?
+        .0;
+    let (_key_guard, key_entry) = db
+        .load_key_entry(
+            &KeyDescriptor {
+                domain: Domain::SELINUX,
+                nspace: 1,
+                alias: Some(TEST_ALIAS.to_string()),
+                blob: None,
+            },
+            KeyType::Client,
+            KeyEntryLoadBits::BOTH,
+            1,
+            |_k, _av| Ok(()),
+        )
+        .unwrap();
+    assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
+
+    db.unbind_key(
+        &KeyDescriptor {
+            domain: Domain::SELINUX,
+            nspace: 1,
+            alias: Some(TEST_ALIAS.to_string()),
+            blob: None,
+        },
+        KeyType::Client,
+        1,
+        |_, _| Ok(()),
+    )
+    .unwrap();
+
+    assert_eq!(
+        Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
+        db.load_key_entry(
+            &KeyDescriptor {
+                domain: Domain::SELINUX,
+                nspace: 1,
+                alias: Some(TEST_ALIAS.to_string()),
+                blob: None,
+            },
+            KeyType::Client,
+            KeyEntryLoadBits::NONE,
+            1,
+            |_k, _av| Ok(()),
+        )
+        .unwrap_err()
+        .root_cause()
+        .downcast_ref::<KsError>()
+    );
+
+    Ok(())
+}
+
+#[test]
+fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
+    let mut db = new_test_db()?;
+    let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
+        .context("test_insert_and_load_full_keyentry_domain_key_id")?
+        .0;
+    let (_, key_entry) = db
+        .load_key_entry(
+            &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
+            KeyType::Client,
+            KeyEntryLoadBits::BOTH,
+            1,
+            |_k, _av| Ok(()),
+        )
+        .unwrap();
+
+    assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
+
+    db.unbind_key(
+        &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
+        KeyType::Client,
+        1,
+        |_, _| Ok(()),
+    )
+    .unwrap();
+
+    assert_eq!(
+        Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
+        db.load_key_entry(
+            &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
+            KeyType::Client,
+            KeyEntryLoadBits::NONE,
+            1,
+            |_k, _av| Ok(()),
+        )
+        .unwrap_err()
+        .root_cause()
+        .downcast_ref::<KsError>()
+    );
+
+    Ok(())
+}
+
+#[test]
+fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
+    let mut db = new_test_db()?;
+    let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
+        .context("test_check_and_update_key_usage_count_with_limited_use_key")?
+        .0;
+    // Update the usage count of the limited use key.
+    db.check_and_update_key_usage_count(key_id)?;
+
+    let (_key_guard, key_entry) = db.load_key_entry(
+        &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
+        KeyType::Client,
+        KeyEntryLoadBits::BOTH,
+        1,
+        |_k, _av| Ok(()),
+    )?;
+
+    // The usage count is decremented now.
+    assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
+
+    Ok(())
+}
+
+#[test]
+fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
+    let mut db = new_test_db()?;
+    let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
+        .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
+        .0;
+    // Update the usage count of the limited use key.
+    db.check_and_update_key_usage_count(key_id).expect(concat!(
+        "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
+        "This should succeed."
+    ));
+
+    // Try to update the exhausted limited use key.
+    let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
+        "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
+        "This should fail."
+    ));
+    assert_eq!(
+        &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
+        e.root_cause().downcast_ref::<KsError>().unwrap()
+    );
+
+    Ok(())
+}
+
+#[test]
+fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
+    let mut db = new_test_db()?;
+    let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
+        .context("test_insert_and_load_full_keyentry_from_grant")?
+        .0;
+
+    let granted_key = db
+        .grant(
+            &KeyDescriptor {
+                domain: Domain::APP,
+                nspace: 0,
+                alias: Some(TEST_ALIAS.to_string()),
+                blob: None,
+            },
+            1,
+            2,
+            key_perm_set![KeyPerm::Use],
+            |_k, _av| Ok(()),
+        )
+        .unwrap();
+
+    debug_dump_grant_table(&mut db)?;
+
+    let (_key_guard, key_entry) = db
+        .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
+            assert_eq!(Domain::GRANT, k.domain);
+            assert!(av.unwrap().includes(KeyPerm::Use));
+            Ok(())
+        })
+        .unwrap();
+
+    assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
+
+    db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
+
+    assert_eq!(
+        Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
+        db.load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::NONE, 2, |_k, _av| Ok(
+            ()
+        ),)
+            .unwrap_err()
+            .root_cause()
+            .downcast_ref::<KsError>()
+    );
+
+    Ok(())
+}
+
+// This test attempts to load a key by key id while the caller is not the owner
+// but a grant exists for the given key and the caller.
+#[test]
+fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
+    let mut db = new_test_db()?;
+    const OWNER_UID: u32 = 1u32;
+    const GRANTEE_UID: u32 = 2u32;
+    const SOMEONE_ELSE_UID: u32 = 3u32;
+    let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
+        .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
+        .0;
+
+    db.grant(
+        &KeyDescriptor {
+            domain: Domain::APP,
+            nspace: 0,
+            alias: Some(TEST_ALIAS.to_string()),
+            blob: None,
+        },
+        OWNER_UID,
+        GRANTEE_UID,
+        key_perm_set![KeyPerm::Use],
+        |_k, _av| Ok(()),
+    )
+    .unwrap();
+
+    debug_dump_grant_table(&mut db)?;
+
+    let id_descriptor =
+        KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
+
+    let (_, key_entry) = db
+        .load_key_entry(
+            &id_descriptor,
+            KeyType::Client,
+            KeyEntryLoadBits::BOTH,
+            GRANTEE_UID,
+            |k, av| {
+                assert_eq!(Domain::APP, k.domain);
+                assert_eq!(OWNER_UID as i64, k.nspace);
+                assert!(av.unwrap().includes(KeyPerm::Use));
+                Ok(())
+            },
+        )
+        .unwrap();
+
+    assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
+
+    let (_, key_entry) = db
+        .load_key_entry(
+            &id_descriptor,
+            KeyType::Client,
+            KeyEntryLoadBits::BOTH,
+            SOMEONE_ELSE_UID,
+            |k, av| {
+                assert_eq!(Domain::APP, k.domain);
+                assert_eq!(OWNER_UID as i64, k.nspace);
+                assert!(av.is_none());
+                Ok(())
+            },
+        )
+        .unwrap();
+
+    assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
+
+    db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
+
+    assert_eq!(
+        Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
+        db.load_key_entry(
+            &id_descriptor,
+            KeyType::Client,
+            KeyEntryLoadBits::NONE,
+            GRANTEE_UID,
+            |_k, _av| Ok(()),
+        )
+        .unwrap_err()
+        .root_cause()
+        .downcast_ref::<KsError>()
+    );
+
+    Ok(())
+}
+
+// Creates a key migrates it to a different location and then tries to access it by the old
+// and new location.
+#[test]
+fn test_migrate_key_app_to_app() -> Result<()> {
+    let mut db = new_test_db()?;
+    const SOURCE_UID: u32 = 1u32;
+    const DESTINATION_UID: u32 = 2u32;
+    static SOURCE_ALIAS: &str = "SOURCE_ALIAS";
+    static DESTINATION_ALIAS: &str = "DESTINATION_ALIAS";
+    let key_id_guard =
+        make_test_key_entry(&mut db, Domain::APP, SOURCE_UID as i64, SOURCE_ALIAS, None)
+            .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
+
+    let source_descriptor: KeyDescriptor = KeyDescriptor {
+        domain: Domain::APP,
+        nspace: -1,
+        alias: Some(SOURCE_ALIAS.to_string()),
+        blob: None,
+    };
+
+    let destination_descriptor: KeyDescriptor = KeyDescriptor {
+        domain: Domain::APP,
+        nspace: -1,
+        alias: Some(DESTINATION_ALIAS.to_string()),
+        blob: None,
+    };
+
+    let key_id = key_id_guard.id();
+
+    db.migrate_key_namespace(key_id_guard, &destination_descriptor, DESTINATION_UID, |_k| Ok(()))
+        .unwrap();
+
+    let (_, key_entry) = db
+        .load_key_entry(
+            &destination_descriptor,
+            KeyType::Client,
+            KeyEntryLoadBits::BOTH,
+            DESTINATION_UID,
+            |k, av| {
+                assert_eq!(Domain::APP, k.domain);
+                assert_eq!(DESTINATION_UID as i64, k.nspace);
+                assert!(av.is_none());
+                Ok(())
+            },
+        )
+        .unwrap();
+
+    assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
+
+    assert_eq!(
+        Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
+        db.load_key_entry(
+            &source_descriptor,
+            KeyType::Client,
+            KeyEntryLoadBits::NONE,
+            SOURCE_UID,
+            |_k, _av| Ok(()),
+        )
+        .unwrap_err()
+        .root_cause()
+        .downcast_ref::<KsError>()
+    );
+
+    Ok(())
+}
+
+// Creates a key migrates it to a different location and then tries to access it by the old
+// and new location.
+#[test]
+fn test_migrate_key_app_to_selinux() -> Result<()> {
+    let mut db = new_test_db()?;
+    const SOURCE_UID: u32 = 1u32;
+    const DESTINATION_UID: u32 = 2u32;
+    const DESTINATION_NAMESPACE: i64 = 1000i64;
+    static SOURCE_ALIAS: &str = "SOURCE_ALIAS";
+    static DESTINATION_ALIAS: &str = "DESTINATION_ALIAS";
+    let key_id_guard =
+        make_test_key_entry(&mut db, Domain::APP, SOURCE_UID as i64, SOURCE_ALIAS, None)
+            .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
+
+    let source_descriptor: KeyDescriptor = KeyDescriptor {
+        domain: Domain::APP,
+        nspace: -1,
+        alias: Some(SOURCE_ALIAS.to_string()),
+        blob: None,
+    };
+
+    let destination_descriptor: KeyDescriptor = KeyDescriptor {
+        domain: Domain::SELINUX,
+        nspace: DESTINATION_NAMESPACE,
+        alias: Some(DESTINATION_ALIAS.to_string()),
+        blob: None,
+    };
+
+    let key_id = key_id_guard.id();
+
+    db.migrate_key_namespace(key_id_guard, &destination_descriptor, DESTINATION_UID, |_k| Ok(()))
+        .unwrap();
+
+    let (_, key_entry) = db
+        .load_key_entry(
+            &destination_descriptor,
+            KeyType::Client,
+            KeyEntryLoadBits::BOTH,
+            DESTINATION_UID,
+            |k, av| {
+                assert_eq!(Domain::SELINUX, k.domain);
+                assert_eq!(DESTINATION_NAMESPACE, k.nspace);
+                assert!(av.is_none());
+                Ok(())
+            },
+        )
+        .unwrap();
+
+    assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
+
+    assert_eq!(
+        Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
+        db.load_key_entry(
+            &source_descriptor,
+            KeyType::Client,
+            KeyEntryLoadBits::NONE,
+            SOURCE_UID,
+            |_k, _av| Ok(()),
+        )
+        .unwrap_err()
+        .root_cause()
+        .downcast_ref::<KsError>()
+    );
+
+    Ok(())
+}
+
+// Creates two keys and tries to migrate the first to the location of the second which
+// is expected to fail.
+#[test]
+fn test_migrate_key_destination_occupied() -> Result<()> {
+    let mut db = new_test_db()?;
+    const SOURCE_UID: u32 = 1u32;
+    const DESTINATION_UID: u32 = 2u32;
+    static SOURCE_ALIAS: &str = "SOURCE_ALIAS";
+    static DESTINATION_ALIAS: &str = "DESTINATION_ALIAS";
+    let key_id_guard =
+        make_test_key_entry(&mut db, Domain::APP, SOURCE_UID as i64, SOURCE_ALIAS, None)
+            .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
+    make_test_key_entry(&mut db, Domain::APP, DESTINATION_UID as i64, DESTINATION_ALIAS, None)
+        .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
+
+    let destination_descriptor: KeyDescriptor = KeyDescriptor {
+        domain: Domain::APP,
+        nspace: -1,
+        alias: Some(DESTINATION_ALIAS.to_string()),
+        blob: None,
+    };
+
+    assert_eq!(
+        Some(&KsError::Rc(ResponseCode::INVALID_ARGUMENT)),
+        db.migrate_key_namespace(key_id_guard, &destination_descriptor, DESTINATION_UID, |_k| Ok(
+            ()
+        ))
+        .unwrap_err()
+        .root_cause()
+        .downcast_ref::<KsError>()
+    );
+
+    Ok(())
+}
+
+#[test]
+fn test_upgrade_0_to_1() {
+    const ALIAS1: &str = "test_upgrade_0_to_1_1";
+    const ALIAS2: &str = "test_upgrade_0_to_1_2";
+    const ALIAS3: &str = "test_upgrade_0_to_1_3";
+    const UID: u32 = 33;
+    let temp_dir = Arc::new(TempDir::new("test_upgrade_0_to_1").unwrap());
+    let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
+    let key_id_untouched1 =
+        make_test_key_entry(&mut db, Domain::APP, UID as i64, ALIAS1, None).unwrap().id();
+    let key_id_untouched2 =
+        make_bootlevel_key_entry(&mut db, Domain::APP, UID as i64, ALIAS2, false).unwrap().id();
+    let key_id_deleted =
+        make_bootlevel_key_entry(&mut db, Domain::APP, UID as i64, ALIAS3, true).unwrap().id();
+
+    let (_, key_entry) = db
+        .load_key_entry(
+            &KeyDescriptor {
+                domain: Domain::APP,
+                nspace: -1,
+                alias: Some(ALIAS1.to_string()),
+                blob: None,
+            },
+            KeyType::Client,
+            KeyEntryLoadBits::BOTH,
+            UID,
+            |k, av| {
+                assert_eq!(Domain::APP, k.domain);
+                assert_eq!(UID as i64, k.nspace);
+                assert!(av.is_none());
+                Ok(())
+            },
+        )
+        .unwrap();
+    assert_eq!(key_entry, make_test_key_entry_test_vector(key_id_untouched1, None));
+    let (_, key_entry) = db
+        .load_key_entry(
+            &KeyDescriptor {
+                domain: Domain::APP,
+                nspace: -1,
+                alias: Some(ALIAS2.to_string()),
+                blob: None,
+            },
+            KeyType::Client,
+            KeyEntryLoadBits::BOTH,
+            UID,
+            |k, av| {
+                assert_eq!(Domain::APP, k.domain);
+                assert_eq!(UID as i64, k.nspace);
+                assert!(av.is_none());
+                Ok(())
+            },
+        )
+        .unwrap();
+    assert_eq!(key_entry, make_bootlevel_test_key_entry_test_vector(key_id_untouched2, false));
+    let (_, key_entry) = db
+        .load_key_entry(
+            &KeyDescriptor {
+                domain: Domain::APP,
+                nspace: -1,
+                alias: Some(ALIAS3.to_string()),
+                blob: None,
+            },
+            KeyType::Client,
+            KeyEntryLoadBits::BOTH,
+            UID,
+            |k, av| {
+                assert_eq!(Domain::APP, k.domain);
+                assert_eq!(UID as i64, k.nspace);
+                assert!(av.is_none());
+                Ok(())
+            },
+        )
+        .unwrap();
+    assert_eq!(key_entry, make_bootlevel_test_key_entry_test_vector(key_id_deleted, true));
+
+    db.with_transaction(Immediate("TX_test"), |tx| KeystoreDB::from_0_to_1(tx).no_gc()).unwrap();
+
+    let (_, key_entry) = db
+        .load_key_entry(
+            &KeyDescriptor {
+                domain: Domain::APP,
+                nspace: -1,
+                alias: Some(ALIAS1.to_string()),
+                blob: None,
+            },
+            KeyType::Client,
+            KeyEntryLoadBits::BOTH,
+            UID,
+            |k, av| {
+                assert_eq!(Domain::APP, k.domain);
+                assert_eq!(UID as i64, k.nspace);
+                assert!(av.is_none());
+                Ok(())
+            },
+        )
+        .unwrap();
+    assert_eq!(key_entry, make_test_key_entry_test_vector(key_id_untouched1, None));
+    let (_, key_entry) = db
+        .load_key_entry(
+            &KeyDescriptor {
+                domain: Domain::APP,
+                nspace: -1,
+                alias: Some(ALIAS2.to_string()),
+                blob: None,
+            },
+            KeyType::Client,
+            KeyEntryLoadBits::BOTH,
+            UID,
+            |k, av| {
+                assert_eq!(Domain::APP, k.domain);
+                assert_eq!(UID as i64, k.nspace);
+                assert!(av.is_none());
+                Ok(())
+            },
+        )
+        .unwrap();
+    assert_eq!(key_entry, make_bootlevel_test_key_entry_test_vector(key_id_untouched2, false));
+    assert_eq!(
+        Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
+        db.load_key_entry(
+            &KeyDescriptor {
+                domain: Domain::APP,
+                nspace: -1,
+                alias: Some(ALIAS3.to_string()),
+                blob: None,
+            },
+            KeyType::Client,
+            KeyEntryLoadBits::BOTH,
+            UID,
+            |k, av| {
+                assert_eq!(Domain::APP, k.domain);
+                assert_eq!(UID as i64, k.nspace);
+                assert!(av.is_none());
+                Ok(())
+            },
+        )
+        .unwrap_err()
+        .root_cause()
+        .downcast_ref::<KsError>()
+    );
+}
+
+static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
+
+#[test]
+fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
+    let handle = {
+        let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
+        let temp_dir_clone = temp_dir.clone();
+        let mut db = KeystoreDB::new(temp_dir.path(), None)?;
+        let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
+            .context("test_insert_and_load_full_keyentry_domain_app")?
+            .0;
+        let (_key_guard, key_entry) = db
+            .load_key_entry(
+                &KeyDescriptor {
+                    domain: Domain::APP,
+                    nspace: 0,
+                    alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
+                    blob: None,
+                },
+                KeyType::Client,
+                KeyEntryLoadBits::BOTH,
+                33,
+                |_k, _av| Ok(()),
+            )
+            .unwrap();
+        assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
+        let state = Arc::new(AtomicU8::new(1));
+        let state2 = state.clone();
+
+        // Spawning a second thread that attempts to acquire the key id lock
+        // for the same key as the primary thread. The primary thread then
+        // waits, thereby forcing the secondary thread into the second stage
+        // of acquiring the lock (see KEY ID LOCK 2/2 above).
+        // The test succeeds if the secondary thread observes the transition
+        // of `state` from 1 to 2, despite having a whole second to overtake
+        // the primary thread.
+        let handle = thread::spawn(move || {
+            let temp_dir = temp_dir_clone;
+            let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
+            assert!(db
+                .load_key_entry(
+                    &KeyDescriptor {
+                        domain: Domain::APP,
+                        nspace: 0,
+                        alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
+                        blob: None,
+                    },
+                    KeyType::Client,
+                    KeyEntryLoadBits::BOTH,
+                    33,
+                    |_k, _av| Ok(()),
+                )
+                .is_ok());
+            // We should only see a 2 here because we can only return
+            // from load_key_entry when the `_key_guard` expires,
+            // which happens at the end of the scope.
+            assert_eq!(2, state2.load(Ordering::Relaxed));
+        });
+
+        thread::sleep(std::time::Duration::from_millis(1000));
+
+        assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
+
+        // Return the handle from this scope so we can join with the
+        // secondary thread after the key id lock has expired.
+        handle
+        // This is where the `_key_guard` goes out of scope,
+        // which is the reason for concurrent load_key_entry on the same key
+        // to unblock.
+    };
+    // Join with the secondary thread and unwrap, to propagate failing asserts to the
+    // main test thread. We will not see failing asserts in secondary threads otherwise.
+    handle.join().unwrap();
+    Ok(())
+}
+
+#[test]
+fn test_database_busy_error_code() {
+    let temp_dir =
+        TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
+
+    let mut db1 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database1.");
+    let mut db2 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database2.");
+
+    let _tx1 = db1
+        .conn
+        .transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)
+        .expect("Failed to create first transaction.");
+
+    let error = db2
+        .conn
+        .transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)
+        .context("Transaction begin failed.")
+        .expect_err("This should fail.");
+    let root_cause = error.root_cause();
+    if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
+        root_cause.downcast_ref::<rusqlite::ffi::Error>()
+    {
+        return;
+    }
+    panic!(
+        "Unexpected error {:?} \n{:?} \n{:?}",
+        error,
+        root_cause,
+        root_cause.downcast_ref::<rusqlite::ffi::Error>()
+    )
+}
+
+#[cfg(disabled)]
+#[test]
+fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
+    let temp_dir = Arc::new(
+        TempDir::new("test_large_number_of_concurrent_db_manipulations_")
+            .expect("Failed to create temp dir."),
+    );
+
+    let test_begin = Instant::now();
+
+    const KEY_COUNT: u32 = 500u32;
+    let mut db =
+        new_test_db_with_gc(temp_dir.path(), |_, _| Ok(())).expect("Failed to open database.");
+    const OPEN_DB_COUNT: u32 = 50u32;
+
+    let mut actual_key_count = KEY_COUNT;
+    // First insert KEY_COUNT keys.
+    for count in 0..KEY_COUNT {
+        if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
+            actual_key_count = count;
+            break;
+        }
+        let alias = format!("test_alias_{}", count);
+        make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
+            .expect("Failed to make key entry.");
+    }
+
+    // Insert more keys from a different thread and into a different namespace.
+    let temp_dir1 = temp_dir.clone();
+    let handle1 = thread::spawn(move || {
+        let mut db =
+            new_test_db_with_gc(temp_dir1.path(), |_, _| Ok(())).expect("Failed to open database.");
+
+        for count in 0..actual_key_count {
+            if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
+                return;
+            }
+            let alias = format!("test_alias_{}", count);
+            make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
+                .expect("Failed to make key entry.");
+        }
+
+        // then unbind them again.
+        for count in 0..actual_key_count {
+            if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
+                return;
+            }
+            let key = KeyDescriptor {
+                domain: Domain::APP,
+                nspace: -1,
+                alias: Some(format!("test_alias_{}", count)),
+                blob: None,
+            };
+            db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
+        }
+    });
+
+    // And start unbinding the first set of keys.
+    let temp_dir2 = temp_dir.clone();
+    let handle2 = thread::spawn(move || {
+        let mut db =
+            new_test_db_with_gc(temp_dir2.path(), |_, _| Ok(())).expect("Failed to open database.");
+
+        for count in 0..actual_key_count {
+            if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
+                return;
+            }
+            let key = KeyDescriptor {
+                domain: Domain::APP,
+                nspace: -1,
+                alias: Some(format!("test_alias_{}", count)),
+                blob: None,
+            };
+            db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
+        }
+    });
+
+    // While a lot of inserting and deleting is going on we have to open database connections
+    // successfully and use them.
+    // This clone is not redundant, because temp_dir needs to be kept alive until db goes
+    // out of scope.
+    #[allow(clippy::redundant_clone)]
+    let temp_dir4 = temp_dir.clone();
+    let handle4 = thread::spawn(move || {
+        for count in 0..OPEN_DB_COUNT {
+            if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
+                return;
+            }
+            let mut db = new_test_db_with_gc(temp_dir4.path(), |_, _| Ok(()))
+                .expect("Failed to open database.");
+
+            let alias = format!("test_alias_{}", count);
+            make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
+                .expect("Failed to make key entry.");
+            let key =
+                KeyDescriptor { domain: Domain::APP, nspace: -1, alias: Some(alias), blob: None };
+            db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
+        }
+    });
+
+    handle1.join().expect("Thread 1 panicked.");
+    handle2.join().expect("Thread 2 panicked.");
+    handle4.join().expect("Thread 4 panicked.");
+
+    Ok(())
+}
+
+#[test]
+fn list() -> Result<()> {
+    let temp_dir = TempDir::new("list_test")?;
+    let mut db = KeystoreDB::new(temp_dir.path(), None)?;
+    static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
+        (Domain::APP, 1, "test1"),
+        (Domain::APP, 1, "test2"),
+        (Domain::APP, 1, "test3"),
+        (Domain::APP, 1, "test4"),
+        (Domain::APP, 1, "test5"),
+        (Domain::APP, 1, "test6"),
+        (Domain::APP, 1, "test7"),
+        (Domain::APP, 2, "test1"),
+        (Domain::APP, 2, "test2"),
+        (Domain::APP, 2, "test3"),
+        (Domain::APP, 2, "test4"),
+        (Domain::APP, 2, "test5"),
+        (Domain::APP, 2, "test6"),
+        (Domain::APP, 2, "test8"),
+        (Domain::SELINUX, 100, "test1"),
+        (Domain::SELINUX, 100, "test2"),
+        (Domain::SELINUX, 100, "test3"),
+        (Domain::SELINUX, 100, "test4"),
+        (Domain::SELINUX, 100, "test5"),
+        (Domain::SELINUX, 100, "test6"),
+        (Domain::SELINUX, 100, "test9"),
+    ];
+
+    let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
+        .iter()
+        .map(|(domain, ns, alias)| {
+            let entry =
+                make_test_key_entry(&mut db, *domain, *ns, alias, None).unwrap_or_else(|e| {
+                    panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
+                });
+            (entry.id(), *ns)
+        })
+        .collect();
+
+    for (domain, namespace) in
+        &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
+    {
+        let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
+            .iter()
+            .filter_map(|(domain, ns, alias)| match ns {
+                ns if *ns == *namespace => Some(KeyDescriptor {
+                    domain: *domain,
+                    nspace: *ns,
+                    alias: Some(alias.to_string()),
+                    blob: None,
+                }),
+                _ => None,
+            })
+            .collect();
+        list_o_descriptors.sort();
+        let mut list_result = db.list_past_alias(*domain, *namespace, KeyType::Client, None)?;
+        list_result.sort();
+        assert_eq!(list_o_descriptors, list_result);
+
+        let mut list_o_ids: Vec<i64> = list_o_descriptors
+            .into_iter()
+            .map(|d| {
+                let (_, entry) = db
+                    .load_key_entry(
+                        &d,
+                        KeyType::Client,
+                        KeyEntryLoadBits::NONE,
+                        *namespace as u32,
+                        |_, _| Ok(()),
+                    )
+                    .unwrap();
+                entry.id()
+            })
+            .collect();
+        list_o_ids.sort_unstable();
+        let mut loaded_entries: Vec<i64> = list_o_keys
+            .iter()
+            .filter_map(|(id, ns)| match ns {
+                ns if *ns == *namespace => Some(*id),
+                _ => None,
+            })
+            .collect();
+        loaded_entries.sort_unstable();
+        assert_eq!(list_o_ids, loaded_entries);
+    }
+    assert_eq!(
+        Vec::<KeyDescriptor>::new(),
+        db.list_past_alias(Domain::SELINUX, 101, KeyType::Client, None)?
+    );
+
+    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)]
+struct KeyEntryRow {
+    id: i64,
+    key_type: KeyType,
+    domain: Option<Domain>,
+    namespace: Option<i64>,
+    alias: Option<String>,
+    state: KeyLifeCycle,
+    km_uuid: Option<Uuid>,
+}
+
+fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
+    db.conn
+        .prepare("SELECT * FROM persistent.keyentry;")?
+        .query_map([], |row| {
+            Ok(KeyEntryRow {
+                id: row.get(0)?,
+                key_type: row.get(1)?,
+                domain: row.get::<_, Option<_>>(2)?.map(Domain),
+                namespace: row.get(3)?,
+                alias: row.get(4)?,
+                state: row.get(5)?,
+                km_uuid: row.get(6)?,
+            })
+        })?
+        .map(|r| r.context("Could not read keyentry row."))
+        .collect::<Result<Vec<_>>>()
+}
+
+fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
+    make_test_params_with_sids(max_usage_count, &[42])
+}
+
+// Note: The parameters and SecurityLevel associations are nonsensical. This
+// collection is only used to check if the parameters are preserved as expected by the
+// database.
+fn make_test_params_with_sids(
+    max_usage_count: Option<i32>,
+    user_secure_ids: &[i64],
+) -> Vec<KeyParameter> {
+    let mut params = vec![
+        KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
+        KeyParameter::new(
+            KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::Algorithm(Algorithm::RSA),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
+        KeyParameter::new(
+            KeyParameterValue::BlockMode(BlockMode::ECB),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::BlockMode(BlockMode::GCM),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
+        KeyParameter::new(
+            KeyParameterValue::Digest(Digest::MD5),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::Digest(Digest::SHA_2_224),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(KeyParameterValue::Digest(Digest::SHA_2_256), SecurityLevel::STRONGBOX),
+        KeyParameter::new(
+            KeyParameterValue::PaddingMode(PaddingMode::NONE),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
+            SecurityLevel::STRONGBOX,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
+        KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
+        KeyParameter::new(
+            KeyParameterValue::EcCurve(EcCurve::P_224),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
+        KeyParameter::new(
+            KeyParameterValue::EcCurve(EcCurve::P_384),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::EcCurve(EcCurve::P_521),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::RSAPublicExponent(3),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(KeyParameterValue::IncludeUniqueID, SecurityLevel::TRUSTED_ENVIRONMENT),
+        KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
+        KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
+        KeyParameter::new(KeyParameterValue::ActiveDateTime(1234567890), SecurityLevel::STRONGBOX),
+        KeyParameter::new(
+            KeyParameterValue::OriginationExpireDateTime(1234567890),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::UsageExpireDateTime(1234567890),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::MinSecondsBetweenOps(1234567890),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::MaxUsesPerBoot(1234567890),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
+        KeyParameter::new(KeyParameterValue::NoAuthRequired, SecurityLevel::TRUSTED_ENVIRONMENT),
+        KeyParameter::new(
+            KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
+        KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
+        KeyParameter::new(
+            KeyParameterValue::TrustedUserPresenceRequired,
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::TrustedConfirmationRequired,
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::UnlockedDeviceRequired,
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
+            SecurityLevel::SOFTWARE,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
+            SecurityLevel::SOFTWARE,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::CreationDateTime(12345677890),
+            SecurityLevel::SOFTWARE,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
+        KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
+        KeyParameter::new(
+            KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
+            SecurityLevel::SOFTWARE,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::AttestationIdSecondIMEI(vec![4u8, 3u8, 1u8, 2u8]),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::VendorPatchLevel(3),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(KeyParameterValue::BootPatchLevel(4), SecurityLevel::TRUSTED_ENVIRONMENT),
+        KeyParameter::new(
+            KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(KeyParameterValue::MacLength(256), SecurityLevel::TRUSTED_ENVIRONMENT),
+        KeyParameter::new(
+            KeyParameterValue::ResetSinceIdRotation,
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+        KeyParameter::new(
+            KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ),
+    ];
+    if let Some(value) = max_usage_count {
+        params.push(KeyParameter::new(
+            KeyParameterValue::UsageCountLimit(value),
+            SecurityLevel::SOFTWARE,
+        ));
+    }
+
+    for sid in user_secure_ids.iter() {
+        params.push(KeyParameter::new(
+            KeyParameterValue::UserSecureID(*sid),
+            SecurityLevel::STRONGBOX,
+        ));
+    }
+    params
+}
+
+pub fn make_test_key_entry(
+    db: &mut KeystoreDB,
+    domain: Domain,
+    namespace: i64,
+    alias: &str,
+    max_usage_count: Option<i32>,
+) -> Result<KeyIdGuard> {
+    make_test_key_entry_with_sids(db, domain, namespace, alias, max_usage_count, &[42])
+}
+
+pub fn make_test_key_entry_with_sids(
+    db: &mut KeystoreDB,
+    domain: Domain,
+    namespace: i64,
+    alias: &str,
+    max_usage_count: Option<i32>,
+    sids: &[i64],
+) -> Result<KeyIdGuard> {
+    let key_id = create_key_entry(db, &domain, &namespace, KeyType::Client, &KEYSTORE_UUID)?;
+    let mut blob_metadata = BlobMetaData::new();
+    blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
+    blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
+    blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
+    blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
+    blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
+
+    db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB), Some(&blob_metadata))?;
+    db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
+    db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
+
+    let params = make_test_params_with_sids(max_usage_count, sids);
+    db.insert_keyparameter(&key_id, &params)?;
+
+    let mut metadata = KeyMetaData::new();
+    metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
+    db.insert_key_metadata(&key_id, &metadata)?;
+    rebind_alias(db, &key_id, alias, domain, namespace)?;
+    Ok(key_id)
+}
+
+fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
+    let params = make_test_params(max_usage_count);
+
+    let mut blob_metadata = BlobMetaData::new();
+    blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
+    blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
+    blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
+    blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
+    blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
+
+    let mut metadata = KeyMetaData::new();
+    metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
+
+    KeyEntry {
+        id: key_id,
+        key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
+        cert: Some(TEST_CERT_BLOB.to_vec()),
+        cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
+        km_uuid: KEYSTORE_UUID,
+        parameters: params,
+        metadata,
+        pure_cert: false,
+    }
+}
+
+pub fn make_bootlevel_key_entry(
+    db: &mut KeystoreDB,
+    domain: Domain,
+    namespace: i64,
+    alias: &str,
+    logical_only: bool,
+) -> Result<KeyIdGuard> {
+    let key_id = create_key_entry(db, &domain, &namespace, KeyType::Client, &KEYSTORE_UUID)?;
+    let mut blob_metadata = BlobMetaData::new();
+    if !logical_only {
+        blob_metadata.add(BlobMetaEntry::MaxBootLevel(3));
+    }
+    blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
+
+    db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB), Some(&blob_metadata))?;
+    db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
+    db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
+
+    let mut params = make_test_params(None);
+    params.push(KeyParameter::new(KeyParameterValue::MaxBootLevel(3), SecurityLevel::KEYSTORE));
+
+    db.insert_keyparameter(&key_id, &params)?;
+
+    let mut metadata = KeyMetaData::new();
+    metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
+    db.insert_key_metadata(&key_id, &metadata)?;
+    rebind_alias(db, &key_id, alias, domain, namespace)?;
+    Ok(key_id)
+}
+
+// Creates an app key that is marked as being superencrypted by the given
+// super key ID and that has the given authentication and unlocked device
+// parameters. This does not actually superencrypt the key blob.
+fn make_superencrypted_key_entry(
+    db: &mut KeystoreDB,
+    namespace: i64,
+    alias: &str,
+    requires_authentication: bool,
+    requires_unlocked_device: bool,
+    super_key_id: i64,
+) -> Result<KeyIdGuard> {
+    let domain = Domain::APP;
+    let key_id = create_key_entry(db, &domain, &namespace, KeyType::Client, &KEYSTORE_UUID)?;
+
+    let mut blob_metadata = BlobMetaData::new();
+    blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
+    blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::KeyId(super_key_id)));
+    db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB), Some(&blob_metadata))?;
+
+    let mut params = vec![];
+    if requires_unlocked_device {
+        params.push(KeyParameter::new(
+            KeyParameterValue::UnlockedDeviceRequired,
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ));
+    }
+    if requires_authentication {
+        params.push(KeyParameter::new(
+            KeyParameterValue::UserSecureID(42),
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        ));
+    }
+    db.insert_keyparameter(&key_id, &params)?;
+
+    let mut metadata = KeyMetaData::new();
+    metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
+    db.insert_key_metadata(&key_id, &metadata)?;
+
+    rebind_alias(db, &key_id, alias, domain, namespace)?;
+    Ok(key_id)
+}
+
+fn make_bootlevel_test_key_entry_test_vector(key_id: i64, logical_only: bool) -> KeyEntry {
+    let mut params = make_test_params(None);
+    params.push(KeyParameter::new(KeyParameterValue::MaxBootLevel(3), SecurityLevel::KEYSTORE));
+
+    let mut blob_metadata = BlobMetaData::new();
+    if !logical_only {
+        blob_metadata.add(BlobMetaEntry::MaxBootLevel(3));
+    }
+    blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
+
+    let mut metadata = KeyMetaData::new();
+    metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
+
+    KeyEntry {
+        id: key_id,
+        key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
+        cert: Some(TEST_CERT_BLOB.to_vec()),
+        cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
+        km_uuid: KEYSTORE_UUID,
+        parameters: params,
+        metadata,
+        pure_cert: false,
+    }
+}
+
+fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
+    let mut stmt = db.conn.prepare(
+        "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
+    )?;
+    let rows =
+        stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>([], |row| {
+            Ok((
+                row.get(0)?,
+                row.get(1)?,
+                row.get(2)?,
+                row.get(3)?,
+                row.get(4)?,
+                row.get(5)?,
+                row.get(6)?,
+            ))
+        })?;
+
+    println!("Key entry table rows:");
+    for r in rows {
+        let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
+        println!(
+            "    id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
+            id, key_type, domain, namespace, alias, state, km_uuid
+        );
+    }
+    Ok(())
+}
+
+fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
+    let mut stmt =
+        db.conn.prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
+    let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>([], |row| {
+        Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
+    })?;
+
+    println!("Grant table rows:");
+    for r in rows {
+        let (id, gt, ki, av) = r.unwrap();
+        println!("    id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
+    }
+    Ok(())
+}
+
+// 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> = const { RefCell::new(0) };
+}
+
+fn reset_random() {
+    RANDOM_COUNTER.with(|counter| {
+        *counter.borrow_mut() = 0;
+    })
+}
+
+pub fn random() -> i64 {
+    RANDOM_COUNTER.with(|counter| {
+        let result = *counter.borrow() / 2;
+        *counter.borrow_mut() += 1;
+        result
+    })
+}
+
+#[test]
+fn test_unbind_keys_for_user() -> Result<()> {
+    let mut db = new_test_db()?;
+    db.unbind_keys_for_user(1)?;
+
+    make_test_key_entry(&mut db, Domain::APP, 210000, TEST_ALIAS, None)?;
+    make_test_key_entry(&mut db, Domain::APP, 110000, TEST_ALIAS, None)?;
+    db.unbind_keys_for_user(2)?;
+
+    assert_eq!(1, db.list_past_alias(Domain::APP, 110000, KeyType::Client, None)?.len());
+    assert_eq!(0, db.list_past_alias(Domain::APP, 210000, KeyType::Client, None)?.len());
+
+    db.unbind_keys_for_user(1)?;
+    assert_eq!(0, db.list_past_alias(Domain::APP, 110000, KeyType::Client, None)?.len());
+
+    Ok(())
+}
+
+#[test]
+fn test_unbind_keys_for_user_removes_superkeys() -> Result<()> {
+    let mut db = new_test_db()?;
+    let super_key = keystore2_crypto::generate_aes256_key()?;
+    let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
+    let (encrypted_super_key, metadata) = SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
+
+    let key_name_enc = SuperKeyType {
+        alias: "test_super_key_1",
+        algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
+        name: "test_super_key_1",
+    };
+
+    let key_name_nonenc = SuperKeyType {
+        alias: "test_super_key_2",
+        algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
+        name: "test_super_key_2",
+    };
+
+    // Install two super keys.
+    db.store_super_key(1, &key_name_nonenc, &super_key, &BlobMetaData::new(), &KeyMetaData::new())?;
+    db.store_super_key(1, &key_name_enc, &encrypted_super_key, &metadata, &KeyMetaData::new())?;
+
+    // Check that both can be found in the database.
+    assert!(db.load_super_key(&key_name_enc, 1)?.is_some());
+    assert!(db.load_super_key(&key_name_nonenc, 1)?.is_some());
+
+    // Install the same keys for a different user.
+    db.store_super_key(2, &key_name_nonenc, &super_key, &BlobMetaData::new(), &KeyMetaData::new())?;
+    db.store_super_key(2, &key_name_enc, &encrypted_super_key, &metadata, &KeyMetaData::new())?;
+
+    // Check that the second pair of keys can be found in the database.
+    assert!(db.load_super_key(&key_name_enc, 2)?.is_some());
+    assert!(db.load_super_key(&key_name_nonenc, 2)?.is_some());
+
+    // Delete all keys for user 1.
+    db.unbind_keys_for_user(1)?;
+
+    // All of user 1's keys should be gone.
+    assert!(db.load_super_key(&key_name_enc, 1)?.is_none());
+    assert!(db.load_super_key(&key_name_nonenc, 1)?.is_none());
+
+    // User 2's keys should not have been touched.
+    assert!(db.load_super_key(&key_name_enc, 2)?.is_some());
+    assert!(db.load_super_key(&key_name_nonenc, 2)?.is_some());
+
+    Ok(())
+}
+
+fn app_key_exists(db: &mut KeystoreDB, nspace: i64, alias: &str) -> Result<bool> {
+    db.key_exists(Domain::APP, nspace, alias, KeyType::Client)
+}
+
+// Tests the unbind_auth_bound_keys_for_user() function.
+#[test]
+fn test_unbind_auth_bound_keys_for_user() -> Result<()> {
+    let mut db = new_test_db()?;
+    let user_id = 1;
+    let nspace: i64 = (user_id * AID_USER_OFFSET).into();
+    let other_user_id = 2;
+    let other_user_nspace: i64 = (other_user_id * AID_USER_OFFSET).into();
+    let super_key_type = &USER_AFTER_FIRST_UNLOCK_SUPER_KEY;
+
+    // Create a superencryption key.
+    let super_key = keystore2_crypto::generate_aes256_key()?;
+    let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
+    let (encrypted_super_key, blob_metadata) =
+        SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
+    db.store_super_key(
+        user_id,
+        super_key_type,
+        &encrypted_super_key,
+        &blob_metadata,
+        &KeyMetaData::new(),
+    )?;
+    let super_key_id = db.load_super_key(super_key_type, user_id)?.unwrap().0 .0;
+
+    // Store 4 superencrypted app keys, one for each possible combination of
+    // (authentication required, unlocked device required).
+    make_superencrypted_key_entry(&mut db, nspace, "noauth_noud", false, false, super_key_id)?;
+    make_superencrypted_key_entry(&mut db, nspace, "noauth_ud", false, true, super_key_id)?;
+    make_superencrypted_key_entry(&mut db, nspace, "auth_noud", true, false, super_key_id)?;
+    make_superencrypted_key_entry(&mut db, nspace, "auth_ud", true, true, super_key_id)?;
+    assert!(app_key_exists(&mut db, nspace, "noauth_noud")?);
+    assert!(app_key_exists(&mut db, nspace, "noauth_ud")?);
+    assert!(app_key_exists(&mut db, nspace, "auth_noud")?);
+    assert!(app_key_exists(&mut db, nspace, "auth_ud")?);
+
+    // Also store a key for a different user that requires authentication.
+    make_superencrypted_key_entry(&mut db, other_user_nspace, "auth_ud", true, true, super_key_id)?;
+
+    db.unbind_auth_bound_keys_for_user(user_id)?;
+
+    // Verify that only the user's app keys that require authentication were
+    // deleted. Keys that require an unlocked device but not authentication
+    // should *not* have been deleted, nor should the super key have been
+    // deleted, nor should other users' keys have been deleted.
+    assert!(db.load_super_key(super_key_type, user_id)?.is_some());
+    assert!(app_key_exists(&mut db, nspace, "noauth_noud")?);
+    assert!(app_key_exists(&mut db, nspace, "noauth_ud")?);
+    assert!(!app_key_exists(&mut db, nspace, "auth_noud")?);
+    assert!(!app_key_exists(&mut db, nspace, "auth_ud")?);
+    assert!(app_key_exists(&mut db, other_user_nspace, "auth_ud")?);
+
+    Ok(())
+}
+
+#[test]
+fn test_store_super_key() -> Result<()> {
+    let mut db = new_test_db()?;
+    let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
+    let super_key = keystore2_crypto::generate_aes256_key()?;
+    let secret_bytes = b"keystore2 is great.";
+    let (encrypted_secret, iv, tag) = keystore2_crypto::aes_gcm_encrypt(secret_bytes, &super_key)?;
+
+    let (encrypted_super_key, metadata) = SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
+    db.store_super_key(
+        1,
+        &USER_AFTER_FIRST_UNLOCK_SUPER_KEY,
+        &encrypted_super_key,
+        &metadata,
+        &KeyMetaData::new(),
+    )?;
+
+    // Check if super key exists.
+    assert!(db.key_exists(
+        Domain::APP,
+        1,
+        USER_AFTER_FIRST_UNLOCK_SUPER_KEY.alias,
+        KeyType::Super
+    )?);
+
+    let (_, key_entry) = db.load_super_key(&USER_AFTER_FIRST_UNLOCK_SUPER_KEY, 1)?.unwrap();
+    let loaded_super_key = SuperKeyManager::extract_super_key_from_key_entry(
+        USER_AFTER_FIRST_UNLOCK_SUPER_KEY.algorithm,
+        key_entry,
+        &pw,
+        None,
+    )?;
+
+    let decrypted_secret_bytes = loaded_super_key.decrypt(&encrypted_secret, &iv, &tag)?;
+    assert_eq!(secret_bytes, &*decrypted_secret_bytes);
+
+    Ok(())
+}
+
+fn get_valid_statsd_storage_types() -> Vec<MetricsStorage> {
+    vec![
+        MetricsStorage::KEY_ENTRY,
+        MetricsStorage::KEY_ENTRY_ID_INDEX,
+        MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX,
+        MetricsStorage::BLOB_ENTRY,
+        MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX,
+        MetricsStorage::KEY_PARAMETER,
+        MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX,
+        MetricsStorage::KEY_METADATA,
+        MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX,
+        MetricsStorage::GRANT,
+        MetricsStorage::AUTH_TOKEN,
+        MetricsStorage::BLOB_METADATA,
+        MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX,
+    ]
+}
+
+/// Perform a simple check to ensure that we can query all the storage types
+/// that are supported by the DB. Check for reasonable values.
+#[test]
+fn test_query_all_valid_table_sizes() -> Result<()> {
+    const PAGE_SIZE: i32 = 4096;
+
+    let mut db = new_test_db()?;
+
+    for t in get_valid_statsd_storage_types() {
+        let stat = db.get_storage_stat(t)?;
+        // AuthToken can be less than a page since it's in a btree, not sqlite
+        // TODO(b/187474736) stop using if-let here
+        if let MetricsStorage::AUTH_TOKEN = t {
+        } else {
+            assert!(stat.size >= PAGE_SIZE);
+        }
+        assert!(stat.size >= stat.unused_size);
+    }
+
+    Ok(())
+}
+
+fn get_storage_stats_map(db: &mut KeystoreDB) -> BTreeMap<i32, StorageStats> {
+    get_valid_statsd_storage_types()
+        .into_iter()
+        .map(|t| (t.0, db.get_storage_stat(t).unwrap()))
+        .collect()
+}
+
+fn assert_storage_increased(
+    db: &mut KeystoreDB,
+    increased_storage_types: Vec<MetricsStorage>,
+    baseline: &mut BTreeMap<i32, StorageStats>,
+) {
+    for storage in increased_storage_types {
+        // Verify the expected storage increased.
+        let new = db.get_storage_stat(storage).unwrap();
+        let old = &baseline[&storage.0];
+        assert!(new.size >= old.size, "{}: {} >= {}", storage.0, new.size, old.size);
+        assert!(
+            new.unused_size <= old.unused_size,
+            "{}: {} <= {}",
+            storage.0,
+            new.unused_size,
+            old.unused_size
+        );
+
+        // Update the baseline with the new value so that it succeeds in the
+        // later comparison.
+        baseline.insert(storage.0, new);
+    }
+
+    // Get an updated map of the storage and verify there were no unexpected changes.
+    let updated_stats = get_storage_stats_map(db);
+    assert_eq!(updated_stats.len(), baseline.len());
+
+    for &k in baseline.keys() {
+        let stringify = |map: &BTreeMap<i32, StorageStats>| -> String {
+            let mut s = String::new();
+            for &k in map.keys() {
+                writeln!(&mut s, "  {}: {}, {}", &k, map[&k].size, map[&k].unused_size)
+                    .expect("string concat failed");
+            }
+            s
+        };
+
+        assert!(
+            updated_stats[&k].size == baseline[&k].size
+                && updated_stats[&k].unused_size == baseline[&k].unused_size,
+            "updated_stats:\n{}\nbaseline:\n{}",
+            stringify(&updated_stats),
+            stringify(baseline)
+        );
+    }
+}
+
+#[test]
+fn test_verify_key_table_size_reporting() -> Result<()> {
+    let mut db = new_test_db()?;
+    let mut working_stats = get_storage_stats_map(&mut db);
+
+    let key_id = create_key_entry(&mut db, &Domain::APP, &42, KeyType::Client, &KEYSTORE_UUID)?;
+    assert_storage_increased(
+        &mut db,
+        vec![
+            MetricsStorage::KEY_ENTRY,
+            MetricsStorage::KEY_ENTRY_ID_INDEX,
+            MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX,
+        ],
+        &mut working_stats,
+    );
+
+    let mut blob_metadata = BlobMetaData::new();
+    blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
+    db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB), None)?;
+    assert_storage_increased(
+        &mut db,
+        vec![
+            MetricsStorage::BLOB_ENTRY,
+            MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX,
+            MetricsStorage::BLOB_METADATA,
+            MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX,
+        ],
+        &mut working_stats,
+    );
+
+    let params = make_test_params(None);
+    db.insert_keyparameter(&key_id, &params)?;
+    assert_storage_increased(
+        &mut db,
+        vec![MetricsStorage::KEY_PARAMETER, MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX],
+        &mut working_stats,
+    );
+
+    let mut metadata = KeyMetaData::new();
+    metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
+    db.insert_key_metadata(&key_id, &metadata)?;
+    assert_storage_increased(
+        &mut db,
+        vec![MetricsStorage::KEY_METADATA, MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX],
+        &mut working_stats,
+    );
+
+    let mut sum = 0;
+    for stat in working_stats.values() {
+        sum += stat.size;
+    }
+    let total = db.get_storage_stat(MetricsStorage::DATABASE)?.size;
+    assert!(sum <= total, "Expected sum <= total. sum: {}, total: {}", sum, total);
+
+    Ok(())
+}
+
+#[test]
+fn test_verify_auth_table_size_reporting() -> Result<()> {
+    let mut db = new_test_db()?;
+    let mut working_stats = get_storage_stats_map(&mut db);
+    db.insert_auth_token(&HardwareAuthToken {
+        challenge: 123,
+        userId: 456,
+        authenticatorId: 789,
+        authenticatorType: kmhw_authenticator_type::ANY,
+        timestamp: Timestamp { milliSeconds: 10 },
+        mac: b"mac".to_vec(),
+    });
+    assert_storage_increased(&mut db, vec![MetricsStorage::AUTH_TOKEN], &mut working_stats);
+    Ok(())
+}
+
+#[test]
+fn test_verify_grant_table_size_reporting() -> Result<()> {
+    const OWNER: i64 = 1;
+    let mut db = new_test_db()?;
+    make_test_key_entry(&mut db, Domain::APP, OWNER, TEST_ALIAS, None)?;
+
+    let mut working_stats = get_storage_stats_map(&mut db);
+    db.grant(
+        &KeyDescriptor {
+            domain: Domain::APP,
+            nspace: 0,
+            alias: Some(TEST_ALIAS.to_string()),
+            blob: None,
+        },
+        OWNER as u32,
+        123,
+        key_perm_set![KeyPerm::Use],
+        |_, _| Ok(()),
+    )?;
+
+    assert_storage_increased(&mut db, vec![MetricsStorage::GRANT], &mut working_stats);
+
+    Ok(())
+}
+
+#[test]
+fn find_auth_token_entry_returns_latest() -> Result<()> {
+    let mut db = new_test_db()?;
+    db.insert_auth_token(&HardwareAuthToken {
+        challenge: 123,
+        userId: 456,
+        authenticatorId: 789,
+        authenticatorType: kmhw_authenticator_type::ANY,
+        timestamp: Timestamp { milliSeconds: 10 },
+        mac: b"mac0".to_vec(),
+    });
+    std::thread::sleep(std::time::Duration::from_millis(1));
+    db.insert_auth_token(&HardwareAuthToken {
+        challenge: 123,
+        userId: 457,
+        authenticatorId: 789,
+        authenticatorType: kmhw_authenticator_type::ANY,
+        timestamp: Timestamp { milliSeconds: 12 },
+        mac: b"mac1".to_vec(),
+    });
+    std::thread::sleep(std::time::Duration::from_millis(1));
+    db.insert_auth_token(&HardwareAuthToken {
+        challenge: 123,
+        userId: 458,
+        authenticatorId: 789,
+        authenticatorType: kmhw_authenticator_type::ANY,
+        timestamp: Timestamp { milliSeconds: 3 },
+        mac: b"mac2".to_vec(),
+    });
+    // All three entries are in the database
+    assert_eq!(db.perboot.auth_tokens_len(), 3);
+    // It selected the most recent timestamp
+    assert_eq!(db.find_auth_token_entry(|_| true).unwrap().auth_token.mac, b"mac2".to_vec());
+    Ok(())
+}
+
+#[test]
+fn test_load_key_descriptor() -> Result<()> {
+    let mut db = new_test_db()?;
+    let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)?.0;
+
+    let key = db.load_key_descriptor(key_id)?.unwrap();
+
+    assert_eq!(key.domain, Domain::APP);
+    assert_eq!(key.nspace, 1);
+    assert_eq!(key.alias, Some(TEST_ALIAS.to_string()));
+
+    // No such id
+    assert_eq!(db.load_key_descriptor(key_id + 1)?, None);
+    Ok(())
+}
+
+#[test]
+fn test_get_list_app_uids_for_sid() -> Result<()> {
+    let uid: i32 = 1;
+    let uid_offset: i64 = (uid as i64) * (AID_USER_OFFSET as i64);
+    let first_sid = 667;
+    let second_sid = 669;
+    let first_app_id: i64 = 123 + uid_offset;
+    let second_app_id: i64 = 456 + uid_offset;
+    let third_app_id: i64 = 789 + uid_offset;
+    let unrelated_app_id: i64 = 1011 + uid_offset;
+    let mut db = new_test_db()?;
+    make_test_key_entry_with_sids(
+        &mut db,
+        Domain::APP,
+        first_app_id,
+        TEST_ALIAS,
+        None,
+        &[first_sid],
+    )
+    .context("test_get_list_app_uids_for_sid")?;
+    make_test_key_entry_with_sids(
+        &mut db,
+        Domain::APP,
+        second_app_id,
+        "alias2",
+        None,
+        &[first_sid],
+    )
+    .context("test_get_list_app_uids_for_sid")?;
+    make_test_key_entry_with_sids(
+        &mut db,
+        Domain::APP,
+        second_app_id,
+        TEST_ALIAS,
+        None,
+        &[second_sid],
+    )
+    .context("test_get_list_app_uids_for_sid")?;
+    make_test_key_entry_with_sids(
+        &mut db,
+        Domain::APP,
+        third_app_id,
+        "alias3",
+        None,
+        &[second_sid],
+    )
+    .context("test_get_list_app_uids_for_sid")?;
+    make_test_key_entry_with_sids(&mut db, Domain::APP, unrelated_app_id, TEST_ALIAS, None, &[])
+        .context("test_get_list_app_uids_for_sid")?;
+
+    let mut first_sid_apps = db.get_app_uids_affected_by_sid(uid, first_sid)?;
+    first_sid_apps.sort();
+    assert_eq!(first_sid_apps, vec![first_app_id, second_app_id]);
+    let mut second_sid_apps = db.get_app_uids_affected_by_sid(uid, second_sid)?;
+    second_sid_apps.sort();
+    assert_eq!(second_sid_apps, vec![second_app_id, third_app_id]);
+    Ok(())
+}
+
+#[test]
+fn test_get_list_app_uids_with_multiple_sids() -> Result<()> {
+    let uid: i32 = 1;
+    let uid_offset: i64 = (uid as i64) * (AID_USER_OFFSET as i64);
+    let first_sid = 667;
+    let second_sid = 669;
+    let third_sid = 772;
+    let first_app_id: i64 = 123 + uid_offset;
+    let second_app_id: i64 = 456 + uid_offset;
+    let mut db = new_test_db()?;
+    make_test_key_entry_with_sids(
+        &mut db,
+        Domain::APP,
+        first_app_id,
+        TEST_ALIAS,
+        None,
+        &[first_sid, second_sid],
+    )
+    .context("test_get_list_app_uids_for_sid")?;
+    make_test_key_entry_with_sids(
+        &mut db,
+        Domain::APP,
+        second_app_id,
+        "alias2",
+        None,
+        &[second_sid, third_sid],
+    )
+    .context("test_get_list_app_uids_for_sid")?;
+
+    let first_sid_apps = db.get_app_uids_affected_by_sid(uid, first_sid)?;
+    assert_eq!(first_sid_apps, vec![first_app_id]);
+
+    let mut second_sid_apps = db.get_app_uids_affected_by_sid(uid, second_sid)?;
+    second_sid_apps.sort();
+    assert_eq!(second_sid_apps, vec![first_app_id, second_app_id]);
+
+    let third_sid_apps = db.get_app_uids_affected_by_sid(uid, third_sid)?;
+    assert_eq!(third_sid_apps, vec![second_app_id]);
+    Ok(())
+}
diff --git a/keystore2/src/error.rs b/keystore2/src/error.rs
index cea4d6b..5e80266 100644
--- a/keystore2/src/error.rs
+++ b/keystore2/src/error.rs
@@ -38,6 +38,9 @@
 use std::cmp::PartialEq;
 use std::ffi::CString;
 
+#[cfg(test)]
+pub mod tests;
+
 /// This is the main Keystore error type. It wraps the Keystore `ResponseCode` generated
 /// from AIDL in the `Rc` variant and Keymint `ErrorCode` in the Km variant.
 #[derive(Debug, thiserror::Error, PartialEq, Eq)]
@@ -232,210 +235,3 @@
         },
     }
 }
-
-#[cfg(test)]
-pub mod tests {
-
-    use super::*;
-    use android_system_keystore2::binder::{
-        ExceptionCode, Result as BinderResult, Status as BinderStatus,
-    };
-    use anyhow::{anyhow, Context};
-
-    fn nested_nested_rc(rc: ResponseCode) -> anyhow::Result<()> {
-        Err(anyhow!(Error::Rc(rc))).context("nested nested rc")
-    }
-
-    fn nested_rc(rc: ResponseCode) -> anyhow::Result<()> {
-        nested_nested_rc(rc).context("nested rc")
-    }
-
-    fn nested_nested_ec(ec: ErrorCode) -> anyhow::Result<()> {
-        Err(anyhow!(Error::Km(ec))).context("nested nested ec")
-    }
-
-    fn nested_ec(ec: ErrorCode) -> anyhow::Result<()> {
-        nested_nested_ec(ec).context("nested ec")
-    }
-
-    fn nested_nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode> {
-        Ok(rc)
-    }
-
-    fn nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode> {
-        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")]
-        Fail = 0,
-    }
-
-    fn nested_nested_other_error() -> anyhow::Result<()> {
-        Err(anyhow!(TestError::Fail)).context("nested nested other error")
-    }
-
-    fn nested_other_error() -> anyhow::Result<()> {
-        nested_nested_other_error().context("nested other error")
-    }
-
-    fn binder_sse_error(sse: i32) -> BinderResult<()> {
-        Err(BinderStatus::new_service_specific_error(sse, None))
-    }
-
-    fn binder_exception(ex: ExceptionCode) -> BinderResult<()> {
-        Err(BinderStatus::new_exception(ex, None))
-    }
-
-    #[test]
-    fn keystore_error_test() -> anyhow::Result<(), String> {
-        android_logger::init_once(
-            android_logger::Config::default()
-                .with_tag("keystore_error_tests")
-                .with_max_level(log::LevelFilter::Debug),
-        );
-        // All Error::Rc(x) get mapped on a service specific error
-        // code of x.
-        for rc in ResponseCode::LOCKED.0..ResponseCode::BACKEND_BUSY.0 {
-            assert_eq!(
-                Result::<(), i32>::Err(rc),
-                nested_rc(ResponseCode(rc))
-                    .map_err(into_logged_binder)
-                    .map_err(|s| s.service_specific_error())
-            );
-        }
-
-        // All Keystore Error::Km(x) get mapped on a service
-        // specific error of x.
-        for ec in ErrorCode::UNKNOWN_ERROR.0..ErrorCode::ROOT_OF_TRUST_ALREADY_SET.0 {
-            assert_eq!(
-                Result::<(), i32>::Err(ec),
-                nested_ec(ErrorCode(ec))
-                    .map_err(into_logged_binder)
-                    .map_err(|s| s.service_specific_error())
-            );
-        }
-
-        // All Keymint errors x received through a Binder Result get mapped on
-        // a service specific error of x.
-        for ec in ErrorCode::UNKNOWN_ERROR.0..ErrorCode::ROOT_OF_TRUST_ALREADY_SET.0 {
-            assert_eq!(
-                Result::<(), i32>::Err(ec),
-                map_km_error(binder_sse_error(ec))
-                    .with_context(|| format!("Km error code: {}.", ec))
-                    .map_err(into_logged_binder)
-                    .map_err(|s| s.service_specific_error())
-            );
-        }
-
-        // map_km_error creates an Error::Binder variant storing
-        // ExceptionCode::SERVICE_SPECIFIC and the given
-        // service specific error.
-        let sse = map_km_error(binder_sse_error(1));
-        assert_eq!(Err(Error::Binder(ExceptionCode::SERVICE_SPECIFIC, 1)), sse);
-        // into_binder then maps it on a service specific error of ResponseCode::SYSTEM_ERROR.
-        assert_eq!(
-            Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR),
-            sse.context("Non negative service specific error.")
-                .map_err(into_logged_binder)
-                .map_err(|s| ResponseCode(s.service_specific_error()))
-        );
-
-        // map_km_error creates a Error::Binder variant storing the given exception code.
-        let binder_exception = map_km_error(binder_exception(ExceptionCode::TRANSACTION_FAILED));
-        assert_eq!(Err(Error::Binder(ExceptionCode::TRANSACTION_FAILED, 0)), binder_exception);
-        // into_binder then maps it on a service specific error of ResponseCode::SYSTEM_ERROR.
-        assert_eq!(
-            Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR),
-            binder_exception
-                .context("Binder Exception.")
-                .map_err(into_logged_binder)
-                .map_err(|s| ResponseCode(s.service_specific_error()))
-        );
-
-        // selinux::Error::Perm() needs to be mapped to ResponseCode::PERMISSION_DENIED
-        assert_eq!(
-            Result::<(), ResponseCode>::Err(ResponseCode::PERMISSION_DENIED),
-            nested_selinux_perm()
-                .map_err(into_logged_binder)
-                .map_err(|s| ResponseCode(s.service_specific_error()))
-        );
-
-        // All other errors get mapped on System Error.
-        assert_eq!(
-            Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR),
-            nested_other_error()
-                .map_err(into_logged_binder)
-                .map_err(|s| ResponseCode(s.service_specific_error()))
-        );
-
-        // Result::Ok variants get passed to the ok handler.
-        assert_eq!(
-            Ok(ResponseCode::LOCKED),
-            nested_ok(ResponseCode::LOCKED).map_err(into_logged_binder)
-        );
-        assert_eq!(
-            Ok(ResponseCode::SYSTEM_ERROR),
-            nested_ok(ResponseCode::SYSTEM_ERROR).map_err(into_logged_binder)
-        );
-
-        Ok(())
-    }
-
-    //Helper function to test whether error cases are handled as expected.
-    pub fn check_result_contains_error_string<T>(
-        result: anyhow::Result<T>,
-        expected_error_string: &str,
-    ) {
-        let error_str = format!(
-            "{:#?}",
-            result.err().unwrap_or_else(|| panic!("Expected the error: {}", expected_error_string))
-        );
-        assert!(
-            error_str.contains(expected_error_string),
-            "The string \"{}\" should contain \"{}\"",
-            error_str,
-            expected_error_string
-        );
-    }
-
-    #[test]
-    fn rkpd_error_is_in_sync_with_response_code() {
-        let error_mapping = [
-            (RkpdError::RequestCancelled, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
-            (RkpdError::GetRegistrationFailed, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
-            (
-                RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_UNKNOWN),
-                ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR,
-            ),
-            (
-                RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_PERMANENT),
-                ResponseCode::OUT_OF_KEYS_PERMANENT_ERROR,
-            ),
-            (
-                RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_PENDING_INTERNET_CONNECTIVITY),
-                ResponseCode::OUT_OF_KEYS_PENDING_INTERNET_CONNECTIVITY,
-            ),
-            (
-                RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_REQUIRES_SECURITY_PATCH),
-                ResponseCode::OUT_OF_KEYS_REQUIRES_SYSTEM_UPGRADE,
-            ),
-            (RkpdError::StoreUpgradedKeyFailed, ResponseCode::SYSTEM_ERROR),
-            (RkpdError::RetryableTimeout, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
-            (RkpdError::Timeout, ResponseCode::SYSTEM_ERROR),
-        ];
-        for (rkpd_error, expected_response_code) in error_mapping {
-            let e: Error = rkpd_error.into();
-            assert_eq!(e, Error::Rc(expected_response_code));
-        }
-    }
-} // mod tests
diff --git a/keystore2/src/error/tests.rs b/keystore2/src/error/tests.rs
new file mode 100644
index 0000000..d50091b
--- /dev/null
+++ b/keystore2/src/error/tests.rs
@@ -0,0 +1,218 @@
+// 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.
+
+//! Error handling tests.
+
+use super::*;
+use android_system_keystore2::binder::{
+    ExceptionCode, Result as BinderResult, Status as BinderStatus,
+};
+use anyhow::{anyhow, Context};
+
+fn nested_nested_rc(rc: ResponseCode) -> anyhow::Result<()> {
+    Err(anyhow!(Error::Rc(rc))).context("nested nested rc")
+}
+
+fn nested_rc(rc: ResponseCode) -> anyhow::Result<()> {
+    nested_nested_rc(rc).context("nested rc")
+}
+
+fn nested_nested_ec(ec: ErrorCode) -> anyhow::Result<()> {
+    Err(anyhow!(Error::Km(ec))).context("nested nested ec")
+}
+
+fn nested_ec(ec: ErrorCode) -> anyhow::Result<()> {
+    nested_nested_ec(ec).context("nested ec")
+}
+
+fn nested_nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode> {
+    Ok(rc)
+}
+
+fn nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode> {
+    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")]
+    Fail = 0,
+}
+
+fn nested_nested_other_error() -> anyhow::Result<()> {
+    Err(anyhow!(TestError::Fail)).context("nested nested other error")
+}
+
+fn nested_other_error() -> anyhow::Result<()> {
+    nested_nested_other_error().context("nested other error")
+}
+
+fn binder_sse_error(sse: i32) -> BinderResult<()> {
+    Err(BinderStatus::new_service_specific_error(sse, None))
+}
+
+fn binder_exception(ex: ExceptionCode) -> BinderResult<()> {
+    Err(BinderStatus::new_exception(ex, None))
+}
+
+#[test]
+fn keystore_error_test() -> anyhow::Result<(), String> {
+    android_logger::init_once(
+        android_logger::Config::default()
+            .with_tag("keystore_error_tests")
+            .with_max_level(log::LevelFilter::Debug),
+    );
+    // All Error::Rc(x) get mapped on a service specific error
+    // code of x.
+    for rc in ResponseCode::LOCKED.0..ResponseCode::BACKEND_BUSY.0 {
+        assert_eq!(
+            Result::<(), i32>::Err(rc),
+            nested_rc(ResponseCode(rc))
+                .map_err(into_logged_binder)
+                .map_err(|s| s.service_specific_error())
+        );
+    }
+
+    // All Keystore Error::Km(x) get mapped on a service
+    // specific error of x.
+    for ec in ErrorCode::UNKNOWN_ERROR.0..ErrorCode::ROOT_OF_TRUST_ALREADY_SET.0 {
+        assert_eq!(
+            Result::<(), i32>::Err(ec),
+            nested_ec(ErrorCode(ec))
+                .map_err(into_logged_binder)
+                .map_err(|s| s.service_specific_error())
+        );
+    }
+
+    // All Keymint errors x received through a Binder Result get mapped on
+    // a service specific error of x.
+    for ec in ErrorCode::UNKNOWN_ERROR.0..ErrorCode::ROOT_OF_TRUST_ALREADY_SET.0 {
+        assert_eq!(
+            Result::<(), i32>::Err(ec),
+            map_km_error(binder_sse_error(ec))
+                .with_context(|| format!("Km error code: {}.", ec))
+                .map_err(into_logged_binder)
+                .map_err(|s| s.service_specific_error())
+        );
+    }
+
+    // map_km_error creates an Error::Binder variant storing
+    // ExceptionCode::SERVICE_SPECIFIC and the given
+    // service specific error.
+    let sse = map_km_error(binder_sse_error(1));
+    assert_eq!(Err(Error::Binder(ExceptionCode::SERVICE_SPECIFIC, 1)), sse);
+    // into_binder then maps it on a service specific error of ResponseCode::SYSTEM_ERROR.
+    assert_eq!(
+        Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR),
+        sse.context("Non negative service specific error.")
+            .map_err(into_logged_binder)
+            .map_err(|s| ResponseCode(s.service_specific_error()))
+    );
+
+    // map_km_error creates a Error::Binder variant storing the given exception code.
+    let binder_exception = map_km_error(binder_exception(ExceptionCode::TRANSACTION_FAILED));
+    assert_eq!(Err(Error::Binder(ExceptionCode::TRANSACTION_FAILED, 0)), binder_exception);
+    // into_binder then maps it on a service specific error of ResponseCode::SYSTEM_ERROR.
+    assert_eq!(
+        Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR),
+        binder_exception
+            .context("Binder Exception.")
+            .map_err(into_logged_binder)
+            .map_err(|s| ResponseCode(s.service_specific_error()))
+    );
+
+    // selinux::Error::Perm() needs to be mapped to ResponseCode::PERMISSION_DENIED
+    assert_eq!(
+        Result::<(), ResponseCode>::Err(ResponseCode::PERMISSION_DENIED),
+        nested_selinux_perm()
+            .map_err(into_logged_binder)
+            .map_err(|s| ResponseCode(s.service_specific_error()))
+    );
+
+    // All other errors get mapped on System Error.
+    assert_eq!(
+        Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR),
+        nested_other_error()
+            .map_err(into_logged_binder)
+            .map_err(|s| ResponseCode(s.service_specific_error()))
+    );
+
+    // Result::Ok variants get passed to the ok handler.
+    assert_eq!(
+        Ok(ResponseCode::LOCKED),
+        nested_ok(ResponseCode::LOCKED).map_err(into_logged_binder)
+    );
+    assert_eq!(
+        Ok(ResponseCode::SYSTEM_ERROR),
+        nested_ok(ResponseCode::SYSTEM_ERROR).map_err(into_logged_binder)
+    );
+
+    Ok(())
+}
+
+//Helper function to test whether error cases are handled as expected.
+pub fn check_result_contains_error_string<T>(
+    result: anyhow::Result<T>,
+    expected_error_string: &str,
+) {
+    let error_str = format!(
+        "{:#?}",
+        result.err().unwrap_or_else(|| panic!("Expected the error: {}", expected_error_string))
+    );
+    assert!(
+        error_str.contains(expected_error_string),
+        "The string \"{}\" should contain \"{}\"",
+        error_str,
+        expected_error_string
+    );
+}
+
+#[test]
+fn rkpd_error_is_in_sync_with_response_code() {
+    let error_mapping = [
+        (RkpdError::RequestCancelled, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
+        (RkpdError::GetRegistrationFailed, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
+        (
+            RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_UNKNOWN),
+            ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR,
+        ),
+        (
+            RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_PERMANENT),
+            ResponseCode::OUT_OF_KEYS_PERMANENT_ERROR,
+        ),
+        (
+            RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_PENDING_INTERNET_CONNECTIVITY),
+            ResponseCode::OUT_OF_KEYS_PENDING_INTERNET_CONNECTIVITY,
+        ),
+        (
+            RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_REQUIRES_SECURITY_PATCH),
+            ResponseCode::OUT_OF_KEYS_REQUIRES_SYSTEM_UPGRADE,
+        ),
+        (RkpdError::StoreUpgradedKeyFailed, ResponseCode::SYSTEM_ERROR),
+        (RkpdError::RetryableTimeout, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
+        (RkpdError::Timeout, ResponseCode::SYSTEM_ERROR),
+    ];
+    for (rkpd_error, expected_response_code) in error_mapping {
+        let e: Error = rkpd_error.into();
+        assert_eq!(e, Error::Rc(expected_response_code));
+    }
+}
diff --git a/keystore2/src/key_parameter.rs b/keystore2/src/key_parameter.rs
index bd45207..466fb50 100644
--- a/keystore2/src/key_parameter.rs
+++ b/keystore2/src/key_parameter.rs
@@ -111,6 +111,18 @@
 use serde::ser::Serializer;
 use serde::{Deserialize, Serialize};
 
+#[cfg(test)]
+mod generated_key_parameter_tests;
+
+#[cfg(test)]
+mod basic_tests;
+
+#[cfg(test)]
+mod storage_tests;
+
+#[cfg(test)]
+mod wire_tests;
+
 /// This trait is used to associate a primitive to any type that can be stored inside a
 /// KeyParameterValue, especially the AIDL enum types, e.g., keymint::{Algorithm, Digest, ...}.
 /// This allows for simplifying the macro rules, e.g., for reading from the SQL database.
@@ -1091,490 +1103,3 @@
         Authorization { securityLevel: self.security_level, keyParameter: self.value.into() }
     }
 }
-
-#[cfg(test)]
-mod generated_key_parameter_tests {
-    use super::*;
-    use android_hardware_security_keymint::aidl::android::hardware::security::keymint::TagType::TagType;
-
-    fn get_field_by_tag_type(tag: Tag) -> KmKeyParameterValue {
-        let tag_type = TagType((tag.0 as u32 & 0xF0000000) as i32);
-        match tag {
-            Tag::ALGORITHM => return KmKeyParameterValue::Algorithm(Default::default()),
-            Tag::BLOCK_MODE => return KmKeyParameterValue::BlockMode(Default::default()),
-            Tag::PADDING => return KmKeyParameterValue::PaddingMode(Default::default()),
-            Tag::DIGEST => return KmKeyParameterValue::Digest(Default::default()),
-            Tag::RSA_OAEP_MGF_DIGEST => return KmKeyParameterValue::Digest(Default::default()),
-            Tag::EC_CURVE => return KmKeyParameterValue::EcCurve(Default::default()),
-            Tag::ORIGIN => return KmKeyParameterValue::Origin(Default::default()),
-            Tag::PURPOSE => return KmKeyParameterValue::KeyPurpose(Default::default()),
-            Tag::USER_AUTH_TYPE => {
-                return KmKeyParameterValue::HardwareAuthenticatorType(Default::default())
-            }
-            Tag::HARDWARE_TYPE => return KmKeyParameterValue::SecurityLevel(Default::default()),
-            _ => {}
-        }
-        match tag_type {
-            TagType::INVALID => return KmKeyParameterValue::Invalid(Default::default()),
-            TagType::ENUM | TagType::ENUM_REP => {}
-            TagType::UINT | TagType::UINT_REP => {
-                return KmKeyParameterValue::Integer(Default::default())
-            }
-            TagType::ULONG | TagType::ULONG_REP => {
-                return KmKeyParameterValue::LongInteger(Default::default())
-            }
-            TagType::DATE => return KmKeyParameterValue::DateTime(Default::default()),
-            TagType::BOOL => return KmKeyParameterValue::BoolValue(Default::default()),
-            TagType::BIGNUM | TagType::BYTES => {
-                return KmKeyParameterValue::Blob(Default::default())
-            }
-            _ => {}
-        }
-        panic!("Unknown tag/tag_type: {:?} {:?}", tag, tag_type);
-    }
-
-    fn check_field_matches_tag_type(list_o_parameters: &[KmKeyParameter]) {
-        for kp in list_o_parameters.iter() {
-            match (&kp.value, get_field_by_tag_type(kp.tag)) {
-                (&KmKeyParameterValue::Algorithm(_), KmKeyParameterValue::Algorithm(_))
-                | (&KmKeyParameterValue::BlockMode(_), KmKeyParameterValue::BlockMode(_))
-                | (&KmKeyParameterValue::PaddingMode(_), KmKeyParameterValue::PaddingMode(_))
-                | (&KmKeyParameterValue::Digest(_), KmKeyParameterValue::Digest(_))
-                | (&KmKeyParameterValue::EcCurve(_), KmKeyParameterValue::EcCurve(_))
-                | (&KmKeyParameterValue::Origin(_), KmKeyParameterValue::Origin(_))
-                | (&KmKeyParameterValue::KeyPurpose(_), KmKeyParameterValue::KeyPurpose(_))
-                | (
-                    &KmKeyParameterValue::HardwareAuthenticatorType(_),
-                    KmKeyParameterValue::HardwareAuthenticatorType(_),
-                )
-                | (&KmKeyParameterValue::SecurityLevel(_), KmKeyParameterValue::SecurityLevel(_))
-                | (&KmKeyParameterValue::Invalid(_), KmKeyParameterValue::Invalid(_))
-                | (&KmKeyParameterValue::Integer(_), KmKeyParameterValue::Integer(_))
-                | (&KmKeyParameterValue::LongInteger(_), KmKeyParameterValue::LongInteger(_))
-                | (&KmKeyParameterValue::DateTime(_), KmKeyParameterValue::DateTime(_))
-                | (&KmKeyParameterValue::BoolValue(_), KmKeyParameterValue::BoolValue(_))
-                | (&KmKeyParameterValue::Blob(_), KmKeyParameterValue::Blob(_)) => {}
-                (actual, expected) => panic!(
-                    "Tag {:?} associated with variant {:?} expected {:?}",
-                    kp.tag, actual, expected
-                ),
-            }
-        }
-    }
-
-    #[test]
-    fn key_parameter_value_field_matches_tag_type() {
-        check_field_matches_tag_type(&KeyParameterValue::make_field_matches_tag_type_test_vector());
-    }
-
-    #[test]
-    fn key_parameter_serialization_test() {
-        let params = KeyParameterValue::make_key_parameter_defaults_vector();
-        let mut out_buffer: Vec<u8> = Default::default();
-        serde_cbor::to_writer(&mut out_buffer, &params)
-            .expect("Failed to serialize key parameters.");
-        let deserialized_params: Vec<KeyParameter> =
-            serde_cbor::from_reader(&mut out_buffer.as_slice())
-                .expect("Failed to deserialize key parameters.");
-        assert_eq!(params, deserialized_params);
-    }
-}
-
-#[cfg(test)]
-mod basic_tests {
-    use crate::key_parameter::*;
-
-    // Test basic functionality of KeyParameter.
-    #[test]
-    fn test_key_parameter() {
-        let key_parameter = KeyParameter::new(
-            KeyParameterValue::Algorithm(Algorithm::RSA),
-            SecurityLevel::STRONGBOX,
-        );
-
-        assert_eq!(key_parameter.get_tag(), Tag::ALGORITHM);
-
-        assert_eq!(
-            *key_parameter.key_parameter_value(),
-            KeyParameterValue::Algorithm(Algorithm::RSA)
-        );
-
-        assert_eq!(*key_parameter.security_level(), SecurityLevel::STRONGBOX);
-    }
-}
-
-/// The storage_tests module first tests the 'new_from_sql' method for KeyParameters of different
-/// data types and then tests 'to_sql' method for KeyParameters of those
-/// different data types. The five different data types for KeyParameter values are:
-/// i) enums of u32
-/// ii) u32
-/// iii) u64
-/// iv) Vec<u8>
-/// v) bool
-#[cfg(test)]
-mod storage_tests {
-    use crate::error::*;
-    use crate::key_parameter::*;
-    use anyhow::Result;
-    use rusqlite::types::ToSql;
-    use rusqlite::{params, Connection};
-
-    /// Test initializing a KeyParameter (with key parameter value corresponding to an enum of i32)
-    /// from a database table row.
-    #[test]
-    fn test_new_from_sql_enum_i32() -> Result<()> {
-        let db = init_db()?;
-        insert_into_keyparameter(
-            &db,
-            1,
-            Tag::ALGORITHM.0,
-            &Algorithm::RSA.0,
-            SecurityLevel::STRONGBOX.0,
-        )?;
-        let key_param = query_from_keyparameter(&db)?;
-        assert_eq!(Tag::ALGORITHM, key_param.get_tag());
-        assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::Algorithm(Algorithm::RSA));
-        assert_eq!(*key_param.security_level(), SecurityLevel::STRONGBOX);
-        Ok(())
-    }
-
-    /// Test initializing a KeyParameter (with key parameter value which is of i32)
-    /// from a database table row.
-    #[test]
-    fn test_new_from_sql_i32() -> Result<()> {
-        let db = init_db()?;
-        insert_into_keyparameter(&db, 1, Tag::KEY_SIZE.0, &1024, SecurityLevel::STRONGBOX.0)?;
-        let key_param = query_from_keyparameter(&db)?;
-        assert_eq!(Tag::KEY_SIZE, key_param.get_tag());
-        assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::KeySize(1024));
-        Ok(())
-    }
-
-    /// Test initializing a KeyParameter (with key parameter value which is of i64)
-    /// from a database table row.
-    #[test]
-    fn test_new_from_sql_i64() -> Result<()> {
-        let db = init_db()?;
-        // max value for i64, just to test corner cases
-        insert_into_keyparameter(
-            &db,
-            1,
-            Tag::RSA_PUBLIC_EXPONENT.0,
-            &(i64::MAX),
-            SecurityLevel::STRONGBOX.0,
-        )?;
-        let key_param = query_from_keyparameter(&db)?;
-        assert_eq!(Tag::RSA_PUBLIC_EXPONENT, key_param.get_tag());
-        assert_eq!(
-            *key_param.key_parameter_value(),
-            KeyParameterValue::RSAPublicExponent(i64::MAX)
-        );
-        Ok(())
-    }
-
-    /// Test initializing a KeyParameter (with key parameter value which is of bool)
-    /// from a database table row.
-    #[test]
-    fn test_new_from_sql_bool() -> Result<()> {
-        let db = init_db()?;
-        insert_into_keyparameter(&db, 1, Tag::CALLER_NONCE.0, &Null, SecurityLevel::STRONGBOX.0)?;
-        let key_param = query_from_keyparameter(&db)?;
-        assert_eq!(Tag::CALLER_NONCE, key_param.get_tag());
-        assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::CallerNonce);
-        Ok(())
-    }
-
-    /// Test initializing a KeyParameter (with key parameter value which is of Vec<u8>)
-    /// from a database table row.
-    #[test]
-    fn test_new_from_sql_vec_u8() -> Result<()> {
-        let db = init_db()?;
-        let app_id = String::from("MyAppID");
-        let app_id_bytes = app_id.into_bytes();
-        insert_into_keyparameter(
-            &db,
-            1,
-            Tag::APPLICATION_ID.0,
-            &app_id_bytes,
-            SecurityLevel::STRONGBOX.0,
-        )?;
-        let key_param = query_from_keyparameter(&db)?;
-        assert_eq!(Tag::APPLICATION_ID, key_param.get_tag());
-        assert_eq!(
-            *key_param.key_parameter_value(),
-            KeyParameterValue::ApplicationID(app_id_bytes)
-        );
-        Ok(())
-    }
-
-    /// Test storing a KeyParameter (with key parameter value which corresponds to an enum of i32)
-    /// in the database
-    #[test]
-    fn test_to_sql_enum_i32() -> Result<()> {
-        let db = init_db()?;
-        let kp = KeyParameter::new(
-            KeyParameterValue::Algorithm(Algorithm::RSA),
-            SecurityLevel::STRONGBOX,
-        );
-        store_keyparameter(&db, 1, &kp)?;
-        let key_param = query_from_keyparameter(&db)?;
-        assert_eq!(kp.get_tag(), key_param.get_tag());
-        assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
-        assert_eq!(kp.security_level(), key_param.security_level());
-        Ok(())
-    }
-
-    /// Test storing a KeyParameter (with key parameter value which is of i32) in the database
-    #[test]
-    fn test_to_sql_i32() -> Result<()> {
-        let db = init_db()?;
-        let kp = KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::STRONGBOX);
-        store_keyparameter(&db, 1, &kp)?;
-        let key_param = query_from_keyparameter(&db)?;
-        assert_eq!(kp.get_tag(), key_param.get_tag());
-        assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
-        assert_eq!(kp.security_level(), key_param.security_level());
-        Ok(())
-    }
-
-    /// Test storing a KeyParameter (with key parameter value which is of i64) in the database
-    #[test]
-    fn test_to_sql_i64() -> Result<()> {
-        let db = init_db()?;
-        // max value for i64, just to test corner cases
-        let kp = KeyParameter::new(
-            KeyParameterValue::RSAPublicExponent(i64::MAX),
-            SecurityLevel::STRONGBOX,
-        );
-        store_keyparameter(&db, 1, &kp)?;
-        let key_param = query_from_keyparameter(&db)?;
-        assert_eq!(kp.get_tag(), key_param.get_tag());
-        assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
-        assert_eq!(kp.security_level(), key_param.security_level());
-        Ok(())
-    }
-
-    /// Test storing a KeyParameter (with key parameter value which is of Vec<u8>) in the database
-    #[test]
-    fn test_to_sql_vec_u8() -> Result<()> {
-        let db = init_db()?;
-        let kp = KeyParameter::new(
-            KeyParameterValue::ApplicationID(String::from("MyAppID").into_bytes()),
-            SecurityLevel::STRONGBOX,
-        );
-        store_keyparameter(&db, 1, &kp)?;
-        let key_param = query_from_keyparameter(&db)?;
-        assert_eq!(kp.get_tag(), key_param.get_tag());
-        assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
-        assert_eq!(kp.security_level(), key_param.security_level());
-        Ok(())
-    }
-
-    /// Test storing a KeyParameter (with key parameter value which is of i32) in the database
-    #[test]
-    fn test_to_sql_bool() -> Result<()> {
-        let db = init_db()?;
-        let kp = KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::STRONGBOX);
-        store_keyparameter(&db, 1, &kp)?;
-        let key_param = query_from_keyparameter(&db)?;
-        assert_eq!(kp.get_tag(), key_param.get_tag());
-        assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
-        assert_eq!(kp.security_level(), key_param.security_level());
-        Ok(())
-    }
-
-    #[test]
-    /// Test Tag::Invalid
-    fn test_invalid_tag() -> Result<()> {
-        let db = init_db()?;
-        insert_into_keyparameter(&db, 1, 0, &123, 1)?;
-        let key_param = query_from_keyparameter(&db)?;
-        assert_eq!(Tag::INVALID, key_param.get_tag());
-        Ok(())
-    }
-
-    #[test]
-    fn test_non_existing_enum_variant() -> Result<()> {
-        let db = init_db()?;
-        insert_into_keyparameter(&db, 1, 100, &123, 1)?;
-        let key_param = query_from_keyparameter(&db)?;
-        assert_eq!(Tag::INVALID, key_param.get_tag());
-        Ok(())
-    }
-
-    #[test]
-    fn test_invalid_conversion_from_sql() -> Result<()> {
-        let db = init_db()?;
-        insert_into_keyparameter(&db, 1, Tag::ALGORITHM.0, &Null, 1)?;
-        tests::check_result_contains_error_string(
-            query_from_keyparameter(&db),
-            "Failed to read sql data for tag: ALGORITHM.",
-        );
-        Ok(())
-    }
-
-    /// Helper method to init database table for key parameter
-    fn init_db() -> Result<Connection> {
-        let db = Connection::open_in_memory().context("Failed to initialize sqlite connection.")?;
-        db.execute("ATTACH DATABASE ? as 'persistent';", params![""])
-            .context("Failed to attach databases.")?;
-        db.execute(
-            "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
-                                keyentryid INTEGER,
-                                tag INTEGER,
-                                data ANY,
-                                security_level INTEGER);",
-            [],
-        )
-        .context("Failed to initialize \"keyparameter\" table.")?;
-        Ok(db)
-    }
-
-    /// Helper method to insert an entry into key parameter table, with individual parameters
-    fn insert_into_keyparameter<T: ToSql>(
-        db: &Connection,
-        key_id: i64,
-        tag: i32,
-        value: &T,
-        security_level: i32,
-    ) -> Result<()> {
-        db.execute(
-            "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
-                VALUES(?, ?, ?, ?);",
-            params![key_id, tag, *value, security_level],
-        )?;
-        Ok(())
-    }
-
-    /// Helper method to store a key parameter instance.
-    fn store_keyparameter(db: &Connection, key_id: i64, kp: &KeyParameter) -> Result<()> {
-        db.execute(
-            "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
-                VALUES(?, ?, ?, ?);",
-            params![key_id, kp.get_tag().0, kp.key_parameter_value(), kp.security_level().0],
-        )?;
-        Ok(())
-    }
-
-    /// Helper method to query a row from keyparameter table
-    fn query_from_keyparameter(db: &Connection) -> Result<KeyParameter> {
-        let mut stmt =
-            db.prepare("SELECT tag, data, security_level FROM persistent.keyparameter")?;
-        let mut rows = stmt.query([])?;
-        let row = rows.next()?.unwrap();
-        KeyParameter::new_from_sql(
-            Tag(row.get(0)?),
-            &SqlField::new(1, row),
-            SecurityLevel(row.get(2)?),
-        )
-    }
-}
-
-/// The wire_tests module tests the 'convert_to_wire' and 'convert_from_wire' methods for
-/// KeyParameter, for the four different types used in KmKeyParameter, in addition to Invalid
-/// key parameter.
-/// i) bool
-/// ii) integer
-/// iii) longInteger
-/// iv) blob
-#[cfg(test)]
-mod wire_tests {
-    use crate::key_parameter::*;
-    /// unit tests for to conversions
-    #[test]
-    fn test_convert_to_wire_invalid() {
-        let kp = KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::STRONGBOX);
-        assert_eq!(
-            KmKeyParameter { tag: Tag::INVALID, value: KmKeyParameterValue::Invalid(0) },
-            kp.value.into()
-        );
-    }
-    #[test]
-    fn test_convert_to_wire_bool() {
-        let kp = KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::STRONGBOX);
-        assert_eq!(
-            KmKeyParameter { tag: Tag::CALLER_NONCE, value: KmKeyParameterValue::BoolValue(true) },
-            kp.value.into()
-        );
-    }
-    #[test]
-    fn test_convert_to_wire_integer() {
-        let kp = KeyParameter::new(
-            KeyParameterValue::KeyPurpose(KeyPurpose::ENCRYPT),
-            SecurityLevel::STRONGBOX,
-        );
-        assert_eq!(
-            KmKeyParameter {
-                tag: Tag::PURPOSE,
-                value: KmKeyParameterValue::KeyPurpose(KeyPurpose::ENCRYPT)
-            },
-            kp.value.into()
-        );
-    }
-    #[test]
-    fn test_convert_to_wire_long_integer() {
-        let kp =
-            KeyParameter::new(KeyParameterValue::UserSecureID(i64::MAX), SecurityLevel::STRONGBOX);
-        assert_eq!(
-            KmKeyParameter {
-                tag: Tag::USER_SECURE_ID,
-                value: KmKeyParameterValue::LongInteger(i64::MAX)
-            },
-            kp.value.into()
-        );
-    }
-    #[test]
-    fn test_convert_to_wire_blob() {
-        let kp = KeyParameter::new(
-            KeyParameterValue::ConfirmationToken(String::from("ConfirmationToken").into_bytes()),
-            SecurityLevel::STRONGBOX,
-        );
-        assert_eq!(
-            KmKeyParameter {
-                tag: Tag::CONFIRMATION_TOKEN,
-                value: KmKeyParameterValue::Blob(String::from("ConfirmationToken").into_bytes())
-            },
-            kp.value.into()
-        );
-    }
-
-    /// unit tests for from conversion
-    #[test]
-    fn test_convert_from_wire_invalid() {
-        let aidl_kp = KmKeyParameter { tag: Tag::INVALID, ..Default::default() };
-        assert_eq!(KeyParameterValue::Invalid, aidl_kp.into());
-    }
-    #[test]
-    fn test_convert_from_wire_bool() {
-        let aidl_kp =
-            KmKeyParameter { tag: Tag::CALLER_NONCE, value: KmKeyParameterValue::BoolValue(true) };
-        assert_eq!(KeyParameterValue::CallerNonce, aidl_kp.into());
-    }
-    #[test]
-    fn test_convert_from_wire_integer() {
-        let aidl_kp = KmKeyParameter {
-            tag: Tag::PURPOSE,
-            value: KmKeyParameterValue::KeyPurpose(KeyPurpose::ENCRYPT),
-        };
-        assert_eq!(KeyParameterValue::KeyPurpose(KeyPurpose::ENCRYPT), aidl_kp.into());
-    }
-    #[test]
-    fn test_convert_from_wire_long_integer() {
-        let aidl_kp = KmKeyParameter {
-            tag: Tag::USER_SECURE_ID,
-            value: KmKeyParameterValue::LongInteger(i64::MAX),
-        };
-        assert_eq!(KeyParameterValue::UserSecureID(i64::MAX), aidl_kp.into());
-    }
-    #[test]
-    fn test_convert_from_wire_blob() {
-        let aidl_kp = KmKeyParameter {
-            tag: Tag::CONFIRMATION_TOKEN,
-            value: KmKeyParameterValue::Blob(String::from("ConfirmationToken").into_bytes()),
-        };
-        assert_eq!(
-            KeyParameterValue::ConfirmationToken(String::from("ConfirmationToken").into_bytes()),
-            aidl_kp.into()
-        );
-    }
-}
diff --git a/keystore2/src/key_parameter/basic_tests.rs b/keystore2/src/key_parameter/basic_tests.rs
new file mode 100644
index 0000000..2bb3724
--- /dev/null
+++ b/keystore2/src/key_parameter/basic_tests.rs
@@ -0,0 +1,28 @@
+// 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.
+
+use crate::key_parameter::*;
+
+// Test basic functionality of KeyParameter.
+#[test]
+fn test_key_parameter() {
+    let key_parameter =
+        KeyParameter::new(KeyParameterValue::Algorithm(Algorithm::RSA), SecurityLevel::STRONGBOX);
+
+    assert_eq!(key_parameter.get_tag(), Tag::ALGORITHM);
+
+    assert_eq!(*key_parameter.key_parameter_value(), KeyParameterValue::Algorithm(Algorithm::RSA));
+
+    assert_eq!(*key_parameter.security_level(), SecurityLevel::STRONGBOX);
+}
diff --git a/keystore2/src/key_parameter/generated_key_parameter_tests.rs b/keystore2/src/key_parameter/generated_key_parameter_tests.rs
new file mode 100644
index 0000000..a5c0a8b
--- /dev/null
+++ b/keystore2/src/key_parameter/generated_key_parameter_tests.rs
@@ -0,0 +1,95 @@
+// 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.
+
+use super::*;
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::TagType::TagType;
+
+fn get_field_by_tag_type(tag: Tag) -> KmKeyParameterValue {
+    let tag_type = TagType((tag.0 as u32 & 0xF0000000) as i32);
+    match tag {
+        Tag::ALGORITHM => return KmKeyParameterValue::Algorithm(Default::default()),
+        Tag::BLOCK_MODE => return KmKeyParameterValue::BlockMode(Default::default()),
+        Tag::PADDING => return KmKeyParameterValue::PaddingMode(Default::default()),
+        Tag::DIGEST => return KmKeyParameterValue::Digest(Default::default()),
+        Tag::RSA_OAEP_MGF_DIGEST => return KmKeyParameterValue::Digest(Default::default()),
+        Tag::EC_CURVE => return KmKeyParameterValue::EcCurve(Default::default()),
+        Tag::ORIGIN => return KmKeyParameterValue::Origin(Default::default()),
+        Tag::PURPOSE => return KmKeyParameterValue::KeyPurpose(Default::default()),
+        Tag::USER_AUTH_TYPE => {
+            return KmKeyParameterValue::HardwareAuthenticatorType(Default::default())
+        }
+        Tag::HARDWARE_TYPE => return KmKeyParameterValue::SecurityLevel(Default::default()),
+        _ => {}
+    }
+    match tag_type {
+        TagType::INVALID => return KmKeyParameterValue::Invalid(Default::default()),
+        TagType::ENUM | TagType::ENUM_REP => {}
+        TagType::UINT | TagType::UINT_REP => {
+            return KmKeyParameterValue::Integer(Default::default())
+        }
+        TagType::ULONG | TagType::ULONG_REP => {
+            return KmKeyParameterValue::LongInteger(Default::default())
+        }
+        TagType::DATE => return KmKeyParameterValue::DateTime(Default::default()),
+        TagType::BOOL => return KmKeyParameterValue::BoolValue(Default::default()),
+        TagType::BIGNUM | TagType::BYTES => return KmKeyParameterValue::Blob(Default::default()),
+        _ => {}
+    }
+    panic!("Unknown tag/tag_type: {:?} {:?}", tag, tag_type);
+}
+
+fn check_field_matches_tag_type(list_o_parameters: &[KmKeyParameter]) {
+    for kp in list_o_parameters.iter() {
+        match (&kp.value, get_field_by_tag_type(kp.tag)) {
+            (&KmKeyParameterValue::Algorithm(_), KmKeyParameterValue::Algorithm(_))
+            | (&KmKeyParameterValue::BlockMode(_), KmKeyParameterValue::BlockMode(_))
+            | (&KmKeyParameterValue::PaddingMode(_), KmKeyParameterValue::PaddingMode(_))
+            | (&KmKeyParameterValue::Digest(_), KmKeyParameterValue::Digest(_))
+            | (&KmKeyParameterValue::EcCurve(_), KmKeyParameterValue::EcCurve(_))
+            | (&KmKeyParameterValue::Origin(_), KmKeyParameterValue::Origin(_))
+            | (&KmKeyParameterValue::KeyPurpose(_), KmKeyParameterValue::KeyPurpose(_))
+            | (
+                &KmKeyParameterValue::HardwareAuthenticatorType(_),
+                KmKeyParameterValue::HardwareAuthenticatorType(_),
+            )
+            | (&KmKeyParameterValue::SecurityLevel(_), KmKeyParameterValue::SecurityLevel(_))
+            | (&KmKeyParameterValue::Invalid(_), KmKeyParameterValue::Invalid(_))
+            | (&KmKeyParameterValue::Integer(_), KmKeyParameterValue::Integer(_))
+            | (&KmKeyParameterValue::LongInteger(_), KmKeyParameterValue::LongInteger(_))
+            | (&KmKeyParameterValue::DateTime(_), KmKeyParameterValue::DateTime(_))
+            | (&KmKeyParameterValue::BoolValue(_), KmKeyParameterValue::BoolValue(_))
+            | (&KmKeyParameterValue::Blob(_), KmKeyParameterValue::Blob(_)) => {}
+            (actual, expected) => panic!(
+                "Tag {:?} associated with variant {:?} expected {:?}",
+                kp.tag, actual, expected
+            ),
+        }
+    }
+}
+
+#[test]
+fn key_parameter_value_field_matches_tag_type() {
+    check_field_matches_tag_type(&KeyParameterValue::make_field_matches_tag_type_test_vector());
+}
+
+#[test]
+fn key_parameter_serialization_test() {
+    let params = KeyParameterValue::make_key_parameter_defaults_vector();
+    let mut out_buffer: Vec<u8> = Default::default();
+    serde_cbor::to_writer(&mut out_buffer, &params).expect("Failed to serialize key parameters.");
+    let deserialized_params: Vec<KeyParameter> =
+        serde_cbor::from_reader(&mut out_buffer.as_slice())
+            .expect("Failed to deserialize key parameters.");
+    assert_eq!(params, deserialized_params);
+}
diff --git a/keystore2/src/key_parameter/storage_tests.rs b/keystore2/src/key_parameter/storage_tests.rs
new file mode 100644
index 0000000..38a57e4
--- /dev/null
+++ b/keystore2/src/key_parameter/storage_tests.rs
@@ -0,0 +1,263 @@
+// 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.
+
+//! The storage_tests module first tests the 'new_from_sql' method for KeyParameters of different
+//! data types and then tests 'to_sql' method for KeyParameters of those
+//! different data types. The five different data types for KeyParameter values are:
+//! i) enums of u32
+//! ii) u32
+//! iii) u64
+//! iv) Vec<u8>
+//! v) bool
+
+use crate::error::*;
+use crate::key_parameter::*;
+use anyhow::Result;
+use rusqlite::types::ToSql;
+use rusqlite::{params, Connection};
+
+/// Test initializing a KeyParameter (with key parameter value corresponding to an enum of i32)
+/// from a database table row.
+#[test]
+fn test_new_from_sql_enum_i32() -> Result<()> {
+    let db = init_db()?;
+    insert_into_keyparameter(
+        &db,
+        1,
+        Tag::ALGORITHM.0,
+        &Algorithm::RSA.0,
+        SecurityLevel::STRONGBOX.0,
+    )?;
+    let key_param = query_from_keyparameter(&db)?;
+    assert_eq!(Tag::ALGORITHM, key_param.get_tag());
+    assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::Algorithm(Algorithm::RSA));
+    assert_eq!(*key_param.security_level(), SecurityLevel::STRONGBOX);
+    Ok(())
+}
+
+/// Test initializing a KeyParameter (with key parameter value which is of i32)
+/// from a database table row.
+#[test]
+fn test_new_from_sql_i32() -> Result<()> {
+    let db = init_db()?;
+    insert_into_keyparameter(&db, 1, Tag::KEY_SIZE.0, &1024, SecurityLevel::STRONGBOX.0)?;
+    let key_param = query_from_keyparameter(&db)?;
+    assert_eq!(Tag::KEY_SIZE, key_param.get_tag());
+    assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::KeySize(1024));
+    Ok(())
+}
+
+/// Test initializing a KeyParameter (with key parameter value which is of i64)
+/// from a database table row.
+#[test]
+fn test_new_from_sql_i64() -> Result<()> {
+    let db = init_db()?;
+    // max value for i64, just to test corner cases
+    insert_into_keyparameter(
+        &db,
+        1,
+        Tag::RSA_PUBLIC_EXPONENT.0,
+        &(i64::MAX),
+        SecurityLevel::STRONGBOX.0,
+    )?;
+    let key_param = query_from_keyparameter(&db)?;
+    assert_eq!(Tag::RSA_PUBLIC_EXPONENT, key_param.get_tag());
+    assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::RSAPublicExponent(i64::MAX));
+    Ok(())
+}
+
+/// Test initializing a KeyParameter (with key parameter value which is of bool)
+/// from a database table row.
+#[test]
+fn test_new_from_sql_bool() -> Result<()> {
+    let db = init_db()?;
+    insert_into_keyparameter(&db, 1, Tag::CALLER_NONCE.0, &Null, SecurityLevel::STRONGBOX.0)?;
+    let key_param = query_from_keyparameter(&db)?;
+    assert_eq!(Tag::CALLER_NONCE, key_param.get_tag());
+    assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::CallerNonce);
+    Ok(())
+}
+
+/// Test initializing a KeyParameter (with key parameter value which is of Vec<u8>)
+/// from a database table row.
+#[test]
+fn test_new_from_sql_vec_u8() -> Result<()> {
+    let db = init_db()?;
+    let app_id = String::from("MyAppID");
+    let app_id_bytes = app_id.into_bytes();
+    insert_into_keyparameter(
+        &db,
+        1,
+        Tag::APPLICATION_ID.0,
+        &app_id_bytes,
+        SecurityLevel::STRONGBOX.0,
+    )?;
+    let key_param = query_from_keyparameter(&db)?;
+    assert_eq!(Tag::APPLICATION_ID, key_param.get_tag());
+    assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::ApplicationID(app_id_bytes));
+    Ok(())
+}
+
+/// Test storing a KeyParameter (with key parameter value which corresponds to an enum of i32)
+/// in the database
+#[test]
+fn test_to_sql_enum_i32() -> Result<()> {
+    let db = init_db()?;
+    let kp =
+        KeyParameter::new(KeyParameterValue::Algorithm(Algorithm::RSA), SecurityLevel::STRONGBOX);
+    store_keyparameter(&db, 1, &kp)?;
+    let key_param = query_from_keyparameter(&db)?;
+    assert_eq!(kp.get_tag(), key_param.get_tag());
+    assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
+    assert_eq!(kp.security_level(), key_param.security_level());
+    Ok(())
+}
+
+/// Test storing a KeyParameter (with key parameter value which is of i32) in the database
+#[test]
+fn test_to_sql_i32() -> Result<()> {
+    let db = init_db()?;
+    let kp = KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::STRONGBOX);
+    store_keyparameter(&db, 1, &kp)?;
+    let key_param = query_from_keyparameter(&db)?;
+    assert_eq!(kp.get_tag(), key_param.get_tag());
+    assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
+    assert_eq!(kp.security_level(), key_param.security_level());
+    Ok(())
+}
+
+/// Test storing a KeyParameter (with key parameter value which is of i64) in the database
+#[test]
+fn test_to_sql_i64() -> Result<()> {
+    let db = init_db()?;
+    // max value for i64, just to test corner cases
+    let kp =
+        KeyParameter::new(KeyParameterValue::RSAPublicExponent(i64::MAX), SecurityLevel::STRONGBOX);
+    store_keyparameter(&db, 1, &kp)?;
+    let key_param = query_from_keyparameter(&db)?;
+    assert_eq!(kp.get_tag(), key_param.get_tag());
+    assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
+    assert_eq!(kp.security_level(), key_param.security_level());
+    Ok(())
+}
+
+/// Test storing a KeyParameter (with key parameter value which is of Vec<u8>) in the database
+#[test]
+fn test_to_sql_vec_u8() -> Result<()> {
+    let db = init_db()?;
+    let kp = KeyParameter::new(
+        KeyParameterValue::ApplicationID(String::from("MyAppID").into_bytes()),
+        SecurityLevel::STRONGBOX,
+    );
+    store_keyparameter(&db, 1, &kp)?;
+    let key_param = query_from_keyparameter(&db)?;
+    assert_eq!(kp.get_tag(), key_param.get_tag());
+    assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
+    assert_eq!(kp.security_level(), key_param.security_level());
+    Ok(())
+}
+
+/// Test storing a KeyParameter (with key parameter value which is of i32) in the database
+#[test]
+fn test_to_sql_bool() -> Result<()> {
+    let db = init_db()?;
+    let kp = KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::STRONGBOX);
+    store_keyparameter(&db, 1, &kp)?;
+    let key_param = query_from_keyparameter(&db)?;
+    assert_eq!(kp.get_tag(), key_param.get_tag());
+    assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
+    assert_eq!(kp.security_level(), key_param.security_level());
+    Ok(())
+}
+
+#[test]
+/// Test Tag::Invalid
+fn test_invalid_tag() -> Result<()> {
+    let db = init_db()?;
+    insert_into_keyparameter(&db, 1, 0, &123, 1)?;
+    let key_param = query_from_keyparameter(&db)?;
+    assert_eq!(Tag::INVALID, key_param.get_tag());
+    Ok(())
+}
+
+#[test]
+fn test_non_existing_enum_variant() -> Result<()> {
+    let db = init_db()?;
+    insert_into_keyparameter(&db, 1, 100, &123, 1)?;
+    let key_param = query_from_keyparameter(&db)?;
+    assert_eq!(Tag::INVALID, key_param.get_tag());
+    Ok(())
+}
+
+#[test]
+fn test_invalid_conversion_from_sql() -> Result<()> {
+    let db = init_db()?;
+    insert_into_keyparameter(&db, 1, Tag::ALGORITHM.0, &Null, 1)?;
+    tests::check_result_contains_error_string(
+        query_from_keyparameter(&db),
+        "Failed to read sql data for tag: ALGORITHM.",
+    );
+    Ok(())
+}
+
+/// Helper method to init database table for key parameter
+fn init_db() -> Result<Connection> {
+    let db = Connection::open_in_memory().context("Failed to initialize sqlite connection.")?;
+    db.execute("ATTACH DATABASE ? as 'persistent';", params![""])
+        .context("Failed to attach databases.")?;
+    db.execute(
+        "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
+                                keyentryid INTEGER,
+                                tag INTEGER,
+                                data ANY,
+                                security_level INTEGER);",
+        [],
+    )
+    .context("Failed to initialize \"keyparameter\" table.")?;
+    Ok(db)
+}
+
+/// Helper method to insert an entry into key parameter table, with individual parameters
+fn insert_into_keyparameter<T: ToSql>(
+    db: &Connection,
+    key_id: i64,
+    tag: i32,
+    value: &T,
+    security_level: i32,
+) -> Result<()> {
+    db.execute(
+        "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
+                VALUES(?, ?, ?, ?);",
+        params![key_id, tag, *value, security_level],
+    )?;
+    Ok(())
+}
+
+/// Helper method to store a key parameter instance.
+fn store_keyparameter(db: &Connection, key_id: i64, kp: &KeyParameter) -> Result<()> {
+    db.execute(
+        "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
+                VALUES(?, ?, ?, ?);",
+        params![key_id, kp.get_tag().0, kp.key_parameter_value(), kp.security_level().0],
+    )?;
+    Ok(())
+}
+
+/// Helper method to query a row from keyparameter table
+fn query_from_keyparameter(db: &Connection) -> Result<KeyParameter> {
+    let mut stmt = db.prepare("SELECT tag, data, security_level FROM persistent.keyparameter")?;
+    let mut rows = stmt.query([])?;
+    let row = rows.next()?.unwrap();
+    KeyParameter::new_from_sql(Tag(row.get(0)?), &SqlField::new(1, row), SecurityLevel(row.get(2)?))
+}
diff --git a/keystore2/src/key_parameter/wire_tests.rs b/keystore2/src/key_parameter/wire_tests.rs
new file mode 100644
index 0000000..278b766
--- /dev/null
+++ b/keystore2/src/key_parameter/wire_tests.rs
@@ -0,0 +1,119 @@
+// 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.
+
+//! The wire_tests module tests the 'convert_to_wire' and 'convert_from_wire' methods for
+//! KeyParameter, for the four different types used in KmKeyParameter, in addition to Invalid
+//! key parameter.
+//! i) bool
+//! ii) integer
+//! iii) longInteger
+//! iv) blob
+
+use crate::key_parameter::*;
+/// unit tests for to conversions
+#[test]
+fn test_convert_to_wire_invalid() {
+    let kp = KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::STRONGBOX);
+    assert_eq!(
+        KmKeyParameter { tag: Tag::INVALID, value: KmKeyParameterValue::Invalid(0) },
+        kp.value.into()
+    );
+}
+#[test]
+fn test_convert_to_wire_bool() {
+    let kp = KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::STRONGBOX);
+    assert_eq!(
+        KmKeyParameter { tag: Tag::CALLER_NONCE, value: KmKeyParameterValue::BoolValue(true) },
+        kp.value.into()
+    );
+}
+#[test]
+fn test_convert_to_wire_integer() {
+    let kp = KeyParameter::new(
+        KeyParameterValue::KeyPurpose(KeyPurpose::ENCRYPT),
+        SecurityLevel::STRONGBOX,
+    );
+    assert_eq!(
+        KmKeyParameter {
+            tag: Tag::PURPOSE,
+            value: KmKeyParameterValue::KeyPurpose(KeyPurpose::ENCRYPT)
+        },
+        kp.value.into()
+    );
+}
+#[test]
+fn test_convert_to_wire_long_integer() {
+    let kp = KeyParameter::new(KeyParameterValue::UserSecureID(i64::MAX), SecurityLevel::STRONGBOX);
+    assert_eq!(
+        KmKeyParameter {
+            tag: Tag::USER_SECURE_ID,
+            value: KmKeyParameterValue::LongInteger(i64::MAX)
+        },
+        kp.value.into()
+    );
+}
+#[test]
+fn test_convert_to_wire_blob() {
+    let kp = KeyParameter::new(
+        KeyParameterValue::ConfirmationToken(String::from("ConfirmationToken").into_bytes()),
+        SecurityLevel::STRONGBOX,
+    );
+    assert_eq!(
+        KmKeyParameter {
+            tag: Tag::CONFIRMATION_TOKEN,
+            value: KmKeyParameterValue::Blob(String::from("ConfirmationToken").into_bytes())
+        },
+        kp.value.into()
+    );
+}
+
+/// unit tests for from conversion
+#[test]
+fn test_convert_from_wire_invalid() {
+    let aidl_kp = KmKeyParameter { tag: Tag::INVALID, ..Default::default() };
+    assert_eq!(KeyParameterValue::Invalid, aidl_kp.into());
+}
+#[test]
+fn test_convert_from_wire_bool() {
+    let aidl_kp =
+        KmKeyParameter { tag: Tag::CALLER_NONCE, value: KmKeyParameterValue::BoolValue(true) };
+    assert_eq!(KeyParameterValue::CallerNonce, aidl_kp.into());
+}
+#[test]
+fn test_convert_from_wire_integer() {
+    let aidl_kp = KmKeyParameter {
+        tag: Tag::PURPOSE,
+        value: KmKeyParameterValue::KeyPurpose(KeyPurpose::ENCRYPT),
+    };
+    assert_eq!(KeyParameterValue::KeyPurpose(KeyPurpose::ENCRYPT), aidl_kp.into());
+}
+#[test]
+fn test_convert_from_wire_long_integer() {
+    let aidl_kp = KmKeyParameter {
+        tag: Tag::USER_SECURE_ID,
+        value: KmKeyParameterValue::LongInteger(i64::MAX),
+    };
+    assert_eq!(KeyParameterValue::UserSecureID(i64::MAX), aidl_kp.into());
+}
+#[test]
+fn test_convert_from_wire_blob() {
+    let aidl_kp = KmKeyParameter {
+        tag: Tag::CONFIRMATION_TOKEN,
+        value: KmKeyParameterValue::Blob(String::from("ConfirmationToken").into_bytes()),
+    };
+    assert_eq!(
+        KeyParameterValue::ConfirmationToken(String::from("ConfirmationToken").into_bytes()),
+        aidl_kp.into()
+    );
+}
diff --git a/keystore2/src/permission.rs b/keystore2/src/permission.rs
index 982bc82..d79445b 100644
--- a/keystore2/src/permission.rs
+++ b/keystore2/src/permission.rs
@@ -38,6 +38,9 @@
 #[cfg(test)]
 use tests::test_getcon as getcon;
 
+#[cfg(test)]
+mod tests;
+
 lazy_static! {
     // Panicking here is allowed because keystore cannot function without this backend
     // and it would happen early and indicate a gross misconfiguration of the device.
@@ -397,433 +400,3 @@
 
     selinux::check_permission(caller_ctx, &target_context, perm)
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use anyhow::anyhow;
-    use anyhow::Result;
-    use keystore2_selinux::*;
-
-    const ALL_PERMS: KeyPermSet = key_perm_set![
-        KeyPerm::ManageBlob,
-        KeyPerm::Delete,
-        KeyPerm::UseDevId,
-        KeyPerm::ReqForcedOp,
-        KeyPerm::GenUniqueId,
-        KeyPerm::Grant,
-        KeyPerm::GetInfo,
-        KeyPerm::Rebind,
-        KeyPerm::Update,
-        KeyPerm::Use,
-        KeyPerm::ConvertStorageKeyToEphemeral,
-    ];
-
-    const SYSTEM_SERVER_PERMISSIONS_NO_GRANT: KeyPermSet = key_perm_set![
-        KeyPerm::Delete,
-        KeyPerm::UseDevId,
-        // No KeyPerm::Grant
-        KeyPerm::GetInfo,
-        KeyPerm::Rebind,
-        KeyPerm::Update,
-        KeyPerm::Use,
-    ];
-
-    const NOT_GRANT_PERMS: KeyPermSet = key_perm_set![
-        KeyPerm::ManageBlob,
-        KeyPerm::Delete,
-        KeyPerm::UseDevId,
-        KeyPerm::ReqForcedOp,
-        KeyPerm::GenUniqueId,
-        // No KeyPerm::Grant
-        KeyPerm::GetInfo,
-        KeyPerm::Rebind,
-        KeyPerm::Update,
-        KeyPerm::Use,
-        KeyPerm::ConvertStorageKeyToEphemeral,
-    ];
-
-    const UNPRIV_PERMS: KeyPermSet = key_perm_set![
-        KeyPerm::Delete,
-        KeyPerm::GetInfo,
-        KeyPerm::Rebind,
-        KeyPerm::Update,
-        KeyPerm::Use,
-    ];
-
-    /// The su_key namespace as defined in su.te and keystore_key_contexts of the
-    /// SePolicy (system/sepolicy).
-    const SU_KEY_NAMESPACE: i32 = 0;
-    /// The shell_key namespace as defined in shell.te and keystore_key_contexts of the
-    /// SePolicy (system/sepolicy).
-    const SHELL_KEY_NAMESPACE: i32 = 1;
-
-    pub fn test_getcon() -> Result<Context> {
-        Context::new("u:object_r:keystore:s0")
-    }
-
-    // This macro evaluates the given expression and checks that
-    // a) evaluated to Result::Err() and that
-    // b) the wrapped error is selinux::Error::perm() (permission denied).
-    // We use a macro here because a function would mask which invocation caused the failure.
-    //
-    // TODO b/164121720 Replace this macro with a function when `track_caller` is available.
-    macro_rules! assert_perm_failed {
-        ($test_function:expr) => {
-            let result = $test_function;
-            assert!(result.is_err(), "Permission check should have failed.");
-            assert_eq!(
-                Some(&selinux::Error::perm()),
-                result.err().unwrap().root_cause().downcast_ref::<selinux::Error>()
-            );
-        };
-    }
-
-    fn check_context() -> Result<(selinux::Context, i32, bool)> {
-        // Calling the non mocked selinux::getcon here intended.
-        let context = selinux::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 check_keystore_permission_test() -> Result<()> {
-        let system_server_ctx = Context::new("u:r:system_server:s0")?;
-        assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::AddAuth).is_ok());
-        assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::ClearNs).is_ok());
-        assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::Lock).is_ok());
-        assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::Reset).is_ok());
-        assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::Unlock).is_ok());
-        assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::ChangeUser).is_ok());
-        assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::ChangePassword).is_ok());
-        assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::ClearUID).is_ok());
-        let shell_ctx = Context::new("u:r:shell:s0")?;
-        assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::AddAuth));
-        assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::ClearNs));
-        assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::List));
-        assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::Lock));
-        assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::Reset));
-        assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::Unlock));
-        assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::ChangeUser));
-        assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::ChangePassword));
-        assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::ClearUID));
-        Ok(())
-    }
-
-    #[test]
-    fn check_grant_permission_app() -> Result<()> {
-        let system_server_ctx = Context::new("u:r:system_server:s0")?;
-        let shell_ctx = Context::new("u:r:shell:s0")?;
-        let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
-        check_grant_permission(&system_server_ctx, SYSTEM_SERVER_PERMISSIONS_NO_GRANT, &key)
-            .expect("Grant permission check failed.");
-
-        // attempts to grant the grant permission must always fail even when privileged.
-        assert_perm_failed!(check_grant_permission(
-            &system_server_ctx,
-            KeyPerm::Grant.into(),
-            &key
-        ));
-        // unprivileged grant attempts always fail. shell does not have the grant permission.
-        assert_perm_failed!(check_grant_permission(&shell_ctx, UNPRIV_PERMS, &key));
-        Ok(())
-    }
-
-    #[test]
-    fn check_grant_permission_selinux() -> Result<()> {
-        let (sctx, namespace, is_su) = check_context()?;
-        let key = KeyDescriptor {
-            domain: Domain::SELINUX,
-            nspace: namespace as i64,
-            alias: None,
-            blob: None,
-        };
-        if is_su {
-            assert!(check_grant_permission(&sctx, NOT_GRANT_PERMS, &key).is_ok());
-            // attempts to grant the grant permission must always fail even when privileged.
-            assert_perm_failed!(check_grant_permission(&sctx, KeyPerm::Grant.into(), &key));
-        } else {
-            // unprivileged grant attempts always fail. shell does not have the grant permission.
-            assert_perm_failed!(check_grant_permission(&sctx, UNPRIV_PERMS, &key));
-        }
-        Ok(())
-    }
-
-    #[test]
-    fn check_key_permission_domain_grant() -> Result<()> {
-        let key = KeyDescriptor { domain: Domain::GRANT, nspace: 0, alias: None, blob: None };
-
-        assert_perm_failed!(check_key_permission(
-            0,
-            &selinux::Context::new("ignored").unwrap(),
-            KeyPerm::Grant,
-            &key,
-            &Some(UNPRIV_PERMS)
-        ));
-
-        check_key_permission(
-            0,
-            &selinux::Context::new("ignored").unwrap(),
-            KeyPerm::Use,
-            &key,
-            &Some(ALL_PERMS),
-        )
-    }
-
-    #[test]
-    fn check_key_permission_domain_app() -> Result<()> {
-        let system_server_ctx = Context::new("u:r:system_server:s0")?;
-        let shell_ctx = Context::new("u:r:shell:s0")?;
-        let gmscore_app = Context::new("u:r:gmscore_app:s0")?;
-
-        let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
-
-        assert!(check_key_permission(0, &system_server_ctx, KeyPerm::Use, &key, &None).is_ok());
-        assert!(check_key_permission(0, &system_server_ctx, KeyPerm::Delete, &key, &None).is_ok());
-        assert!(check_key_permission(0, &system_server_ctx, KeyPerm::GetInfo, &key, &None).is_ok());
-        assert!(check_key_permission(0, &system_server_ctx, KeyPerm::Rebind, &key, &None).is_ok());
-        assert!(check_key_permission(0, &system_server_ctx, KeyPerm::Update, &key, &None).is_ok());
-        assert!(check_key_permission(0, &system_server_ctx, KeyPerm::Grant, &key, &None).is_ok());
-        assert!(check_key_permission(0, &system_server_ctx, KeyPerm::UseDevId, &key, &None).is_ok());
-        assert!(check_key_permission(0, &gmscore_app, KeyPerm::GenUniqueId, &key, &None).is_ok());
-
-        assert!(check_key_permission(0, &shell_ctx, KeyPerm::Use, &key, &None).is_ok());
-        assert!(check_key_permission(0, &shell_ctx, KeyPerm::Delete, &key, &None).is_ok());
-        assert!(check_key_permission(0, &shell_ctx, KeyPerm::GetInfo, &key, &None).is_ok());
-        assert!(check_key_permission(0, &shell_ctx, KeyPerm::Rebind, &key, &None).is_ok());
-        assert!(check_key_permission(0, &shell_ctx, KeyPerm::Update, &key, &None).is_ok());
-        assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::Grant, &key, &None));
-        assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::ReqForcedOp, &key, &None));
-        assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::ManageBlob, &key, &None));
-        assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::UseDevId, &key, &None));
-        assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::GenUniqueId, &key, &None));
-
-        // Also make sure that the permission fails if the caller is not the owner.
-        assert_perm_failed!(check_key_permission(
-            1, // the owner is 0
-            &system_server_ctx,
-            KeyPerm::Use,
-            &key,
-            &None
-        ));
-        // Unless there was a grant.
-        assert!(check_key_permission(
-            1,
-            &system_server_ctx,
-            KeyPerm::Use,
-            &key,
-            &Some(key_perm_set![KeyPerm::Use])
-        )
-        .is_ok());
-        // But fail if the grant did not cover the requested permission.
-        assert_perm_failed!(check_key_permission(
-            1,
-            &system_server_ctx,
-            KeyPerm::Use,
-            &key,
-            &Some(key_perm_set![KeyPerm::GetInfo])
-        ));
-
-        Ok(())
-    }
-
-    #[test]
-    fn check_key_permission_domain_selinux() -> Result<()> {
-        let (sctx, namespace, is_su) = check_context()?;
-        let key = KeyDescriptor {
-            domain: Domain::SELINUX,
-            nspace: namespace as i64,
-            alias: None,
-            blob: None,
-        };
-
-        assert!(check_key_permission(0, &sctx, KeyPerm::Use, &key, &None).is_ok());
-        assert!(check_key_permission(0, &sctx, KeyPerm::Delete, &key, &None).is_ok());
-        assert!(check_key_permission(0, &sctx, KeyPerm::GetInfo, &key, &None).is_ok());
-        assert!(check_key_permission(0, &sctx, KeyPerm::Rebind, &key, &None).is_ok());
-        assert!(check_key_permission(0, &sctx, KeyPerm::Update, &key, &None).is_ok());
-
-        if is_su {
-            assert!(check_key_permission(0, &sctx, KeyPerm::Grant, &key, &None).is_ok());
-            assert!(check_key_permission(0, &sctx, KeyPerm::ManageBlob, &key, &None).is_ok());
-            assert!(check_key_permission(0, &sctx, KeyPerm::UseDevId, &key, &None).is_ok());
-            assert!(check_key_permission(0, &sctx, KeyPerm::GenUniqueId, &key, &None).is_ok());
-            assert!(check_key_permission(0, &sctx, KeyPerm::ReqForcedOp, &key, &None).is_ok());
-        } else {
-            assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::Grant, &key, &None));
-            assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::ReqForcedOp, &key, &None));
-            assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::ManageBlob, &key, &None));
-            assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::UseDevId, &key, &None));
-            assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::GenUniqueId, &key, &None));
-        }
-        Ok(())
-    }
-
-    #[test]
-    fn check_key_permission_domain_blob() -> Result<()> {
-        let (sctx, namespace, is_su) = check_context()?;
-        let key = KeyDescriptor {
-            domain: Domain::BLOB,
-            nspace: namespace as i64,
-            alias: None,
-            blob: None,
-        };
-
-        if is_su {
-            check_key_permission(0, &sctx, KeyPerm::Use, &key, &None)
-        } else {
-            assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::Use, &key, &None));
-            Ok(())
-        }
-    }
-
-    #[test]
-    fn check_key_permission_domain_key_id() -> Result<()> {
-        let key = KeyDescriptor { domain: Domain::KEY_ID, nspace: 0, alias: None, blob: None };
-
-        assert_eq!(
-            Some(&KsError::sys()),
-            check_key_permission(
-                0,
-                &selinux::Context::new("ignored").unwrap(),
-                KeyPerm::Use,
-                &key,
-                &None
-            )
-            .err()
-            .unwrap()
-            .root_cause()
-            .downcast_ref::<KsError>()
-        );
-        Ok(())
-    }
-
-    #[test]
-    fn key_perm_set_all_test() {
-        let v = key_perm_set![
-            KeyPerm::ManageBlob,
-            KeyPerm::Delete,
-            KeyPerm::UseDevId,
-            KeyPerm::ReqForcedOp,
-            KeyPerm::GenUniqueId,
-            KeyPerm::Grant,
-            KeyPerm::GetInfo,
-            KeyPerm::Rebind,
-            KeyPerm::Update,
-            KeyPerm::Use // Test if the macro accepts missing comma at the end of the list.
-        ];
-        let mut i = v.into_iter();
-        assert_eq!(i.next().unwrap().name(), "delete");
-        assert_eq!(i.next().unwrap().name(), "gen_unique_id");
-        assert_eq!(i.next().unwrap().name(), "get_info");
-        assert_eq!(i.next().unwrap().name(), "grant");
-        assert_eq!(i.next().unwrap().name(), "manage_blob");
-        assert_eq!(i.next().unwrap().name(), "rebind");
-        assert_eq!(i.next().unwrap().name(), "req_forced_op");
-        assert_eq!(i.next().unwrap().name(), "update");
-        assert_eq!(i.next().unwrap().name(), "use");
-        assert_eq!(i.next().unwrap().name(), "use_dev_id");
-        assert_eq!(None, i.next());
-    }
-    #[test]
-    fn key_perm_set_sparse_test() {
-        let v = key_perm_set![
-            KeyPerm::ManageBlob,
-            KeyPerm::ReqForcedOp,
-            KeyPerm::GenUniqueId,
-            KeyPerm::Update,
-            KeyPerm::Use, // Test if macro accepts the comma at the end of the list.
-        ];
-        let mut i = v.into_iter();
-        assert_eq!(i.next().unwrap().name(), "gen_unique_id");
-        assert_eq!(i.next().unwrap().name(), "manage_blob");
-        assert_eq!(i.next().unwrap().name(), "req_forced_op");
-        assert_eq!(i.next().unwrap().name(), "update");
-        assert_eq!(i.next().unwrap().name(), "use");
-        assert_eq!(None, i.next());
-    }
-    #[test]
-    fn key_perm_set_empty_test() {
-        let v = key_perm_set![];
-        let mut i = v.into_iter();
-        assert_eq!(None, i.next());
-    }
-    #[test]
-    fn key_perm_set_include_subset_test() {
-        let v1 = key_perm_set![
-            KeyPerm::ManageBlob,
-            KeyPerm::Delete,
-            KeyPerm::UseDevId,
-            KeyPerm::ReqForcedOp,
-            KeyPerm::GenUniqueId,
-            KeyPerm::Grant,
-            KeyPerm::GetInfo,
-            KeyPerm::Rebind,
-            KeyPerm::Update,
-            KeyPerm::Use,
-        ];
-        let v2 = key_perm_set![
-            KeyPerm::ManageBlob,
-            KeyPerm::Delete,
-            KeyPerm::Rebind,
-            KeyPerm::Update,
-            KeyPerm::Use,
-        ];
-        assert!(v1.includes(v2));
-        assert!(!v2.includes(v1));
-    }
-    #[test]
-    fn key_perm_set_include_equal_test() {
-        let v1 = key_perm_set![
-            KeyPerm::ManageBlob,
-            KeyPerm::Delete,
-            KeyPerm::Rebind,
-            KeyPerm::Update,
-            KeyPerm::Use,
-        ];
-        let v2 = key_perm_set![
-            KeyPerm::ManageBlob,
-            KeyPerm::Delete,
-            KeyPerm::Rebind,
-            KeyPerm::Update,
-            KeyPerm::Use,
-        ];
-        assert!(v1.includes(v2));
-        assert!(v2.includes(v1));
-    }
-    #[test]
-    fn key_perm_set_include_overlap_test() {
-        let v1 = key_perm_set![
-            KeyPerm::ManageBlob,
-            KeyPerm::Delete,
-            KeyPerm::Grant, // only in v1
-            KeyPerm::Rebind,
-            KeyPerm::Update,
-            KeyPerm::Use,
-        ];
-        let v2 = key_perm_set![
-            KeyPerm::ManageBlob,
-            KeyPerm::Delete,
-            KeyPerm::ReqForcedOp, // only in v2
-            KeyPerm::Rebind,
-            KeyPerm::Update,
-            KeyPerm::Use,
-        ];
-        assert!(!v1.includes(v2));
-        assert!(!v2.includes(v1));
-    }
-    #[test]
-    fn key_perm_set_include_no_overlap_test() {
-        let v1 = key_perm_set![KeyPerm::ManageBlob, KeyPerm::Delete, KeyPerm::Grant,];
-        let v2 =
-            key_perm_set![KeyPerm::ReqForcedOp, KeyPerm::Rebind, KeyPerm::Update, KeyPerm::Use,];
-        assert!(!v1.includes(v2));
-        assert!(!v2.includes(v1));
-    }
-}
diff --git a/keystore2/src/permission/tests.rs b/keystore2/src/permission/tests.rs
new file mode 100644
index 0000000..f555c12
--- /dev/null
+++ b/keystore2/src/permission/tests.rs
@@ -0,0 +1,434 @@
+// 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.
+
+//! Access control tests.
+
+use super::*;
+use crate::key_perm_set;
+use anyhow::anyhow;
+use anyhow::Result;
+use keystore2_selinux::*;
+
+const ALL_PERMS: KeyPermSet = key_perm_set![
+    KeyPerm::ManageBlob,
+    KeyPerm::Delete,
+    KeyPerm::UseDevId,
+    KeyPerm::ReqForcedOp,
+    KeyPerm::GenUniqueId,
+    KeyPerm::Grant,
+    KeyPerm::GetInfo,
+    KeyPerm::Rebind,
+    KeyPerm::Update,
+    KeyPerm::Use,
+    KeyPerm::ConvertStorageKeyToEphemeral,
+];
+
+const SYSTEM_SERVER_PERMISSIONS_NO_GRANT: KeyPermSet = key_perm_set![
+    KeyPerm::Delete,
+    KeyPerm::UseDevId,
+    // No KeyPerm::Grant
+    KeyPerm::GetInfo,
+    KeyPerm::Rebind,
+    KeyPerm::Update,
+    KeyPerm::Use,
+];
+
+const NOT_GRANT_PERMS: KeyPermSet = key_perm_set![
+    KeyPerm::ManageBlob,
+    KeyPerm::Delete,
+    KeyPerm::UseDevId,
+    KeyPerm::ReqForcedOp,
+    KeyPerm::GenUniqueId,
+    // No KeyPerm::Grant
+    KeyPerm::GetInfo,
+    KeyPerm::Rebind,
+    KeyPerm::Update,
+    KeyPerm::Use,
+    KeyPerm::ConvertStorageKeyToEphemeral,
+];
+
+const UNPRIV_PERMS: KeyPermSet = key_perm_set![
+    KeyPerm::Delete,
+    KeyPerm::GetInfo,
+    KeyPerm::Rebind,
+    KeyPerm::Update,
+    KeyPerm::Use,
+];
+
+/// The su_key namespace as defined in su.te and keystore_key_contexts of the
+/// SePolicy (system/sepolicy).
+const SU_KEY_NAMESPACE: i32 = 0;
+/// The shell_key namespace as defined in shell.te and keystore_key_contexts of the
+/// SePolicy (system/sepolicy).
+const SHELL_KEY_NAMESPACE: i32 = 1;
+
+pub fn test_getcon() -> Result<Context> {
+    Context::new("u:object_r:keystore:s0")
+}
+
+// This macro evaluates the given expression and checks that
+// a) evaluated to Result::Err() and that
+// b) the wrapped error is selinux::Error::perm() (permission denied).
+// We use a macro here because a function would mask which invocation caused the failure.
+//
+// TODO b/164121720 Replace this macro with a function when `track_caller` is available.
+macro_rules! assert_perm_failed {
+    ($test_function:expr) => {
+        let result = $test_function;
+        assert!(result.is_err(), "Permission check should have failed.");
+        assert_eq!(
+            Some(&selinux::Error::perm()),
+            result.err().unwrap().root_cause().downcast_ref::<selinux::Error>()
+        );
+    };
+}
+
+fn check_context() -> Result<(selinux::Context, i32, bool)> {
+    // Calling the non mocked selinux::getcon here intended.
+    let context = selinux::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 check_keystore_permission_test() -> Result<()> {
+    let system_server_ctx = Context::new("u:r:system_server:s0")?;
+    assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::AddAuth).is_ok());
+    assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::ClearNs).is_ok());
+    assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::Lock).is_ok());
+    assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::Reset).is_ok());
+    assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::Unlock).is_ok());
+    assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::ChangeUser).is_ok());
+    assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::ChangePassword).is_ok());
+    assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::ClearUID).is_ok());
+    let shell_ctx = Context::new("u:r:shell:s0")?;
+    assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::AddAuth));
+    assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::ClearNs));
+    assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::List));
+    assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::Lock));
+    assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::Reset));
+    assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::Unlock));
+    assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::ChangeUser));
+    assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::ChangePassword));
+    assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::ClearUID));
+    Ok(())
+}
+
+#[test]
+fn check_grant_permission_app() -> Result<()> {
+    let system_server_ctx = Context::new("u:r:system_server:s0")?;
+    let shell_ctx = Context::new("u:r:shell:s0")?;
+    let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
+    check_grant_permission(&system_server_ctx, SYSTEM_SERVER_PERMISSIONS_NO_GRANT, &key)
+        .expect("Grant permission check failed.");
+
+    // attempts to grant the grant permission must always fail even when privileged.
+    assert_perm_failed!(check_grant_permission(&system_server_ctx, KeyPerm::Grant.into(), &key));
+    // unprivileged grant attempts always fail. shell does not have the grant permission.
+    assert_perm_failed!(check_grant_permission(&shell_ctx, UNPRIV_PERMS, &key));
+    Ok(())
+}
+
+#[test]
+fn check_grant_permission_selinux() -> Result<()> {
+    let (sctx, namespace, is_su) = check_context()?;
+    let key = KeyDescriptor {
+        domain: Domain::SELINUX,
+        nspace: namespace as i64,
+        alias: None,
+        blob: None,
+    };
+    if is_su {
+        assert!(check_grant_permission(&sctx, NOT_GRANT_PERMS, &key).is_ok());
+        // attempts to grant the grant permission must always fail even when privileged.
+        assert_perm_failed!(check_grant_permission(&sctx, KeyPerm::Grant.into(), &key));
+    } else {
+        // unprivileged grant attempts always fail. shell does not have the grant permission.
+        assert_perm_failed!(check_grant_permission(&sctx, UNPRIV_PERMS, &key));
+    }
+    Ok(())
+}
+
+#[test]
+fn check_key_permission_domain_grant() -> Result<()> {
+    let key = KeyDescriptor { domain: Domain::GRANT, nspace: 0, alias: None, blob: None };
+
+    assert_perm_failed!(check_key_permission(
+        0,
+        &selinux::Context::new("ignored").unwrap(),
+        KeyPerm::Grant,
+        &key,
+        &Some(UNPRIV_PERMS)
+    ));
+
+    check_key_permission(
+        0,
+        &selinux::Context::new("ignored").unwrap(),
+        KeyPerm::Use,
+        &key,
+        &Some(ALL_PERMS),
+    )
+}
+
+#[test]
+fn check_key_permission_domain_app() -> Result<()> {
+    let system_server_ctx = Context::new("u:r:system_server:s0")?;
+    let shell_ctx = Context::new("u:r:shell:s0")?;
+    let gmscore_app = Context::new("u:r:gmscore_app:s0")?;
+
+    let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
+
+    assert!(check_key_permission(0, &system_server_ctx, KeyPerm::Use, &key, &None).is_ok());
+    assert!(check_key_permission(0, &system_server_ctx, KeyPerm::Delete, &key, &None).is_ok());
+    assert!(check_key_permission(0, &system_server_ctx, KeyPerm::GetInfo, &key, &None).is_ok());
+    assert!(check_key_permission(0, &system_server_ctx, KeyPerm::Rebind, &key, &None).is_ok());
+    assert!(check_key_permission(0, &system_server_ctx, KeyPerm::Update, &key, &None).is_ok());
+    assert!(check_key_permission(0, &system_server_ctx, KeyPerm::Grant, &key, &None).is_ok());
+    assert!(check_key_permission(0, &system_server_ctx, KeyPerm::UseDevId, &key, &None).is_ok());
+    assert!(check_key_permission(0, &gmscore_app, KeyPerm::GenUniqueId, &key, &None).is_ok());
+
+    assert!(check_key_permission(0, &shell_ctx, KeyPerm::Use, &key, &None).is_ok());
+    assert!(check_key_permission(0, &shell_ctx, KeyPerm::Delete, &key, &None).is_ok());
+    assert!(check_key_permission(0, &shell_ctx, KeyPerm::GetInfo, &key, &None).is_ok());
+    assert!(check_key_permission(0, &shell_ctx, KeyPerm::Rebind, &key, &None).is_ok());
+    assert!(check_key_permission(0, &shell_ctx, KeyPerm::Update, &key, &None).is_ok());
+    assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::Grant, &key, &None));
+    assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::ReqForcedOp, &key, &None));
+    assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::ManageBlob, &key, &None));
+    assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::UseDevId, &key, &None));
+    assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::GenUniqueId, &key, &None));
+
+    // Also make sure that the permission fails if the caller is not the owner.
+    assert_perm_failed!(check_key_permission(
+        1, // the owner is 0
+        &system_server_ctx,
+        KeyPerm::Use,
+        &key,
+        &None
+    ));
+    // Unless there was a grant.
+    assert!(check_key_permission(
+        1,
+        &system_server_ctx,
+        KeyPerm::Use,
+        &key,
+        &Some(key_perm_set![KeyPerm::Use])
+    )
+    .is_ok());
+    // But fail if the grant did not cover the requested permission.
+    assert_perm_failed!(check_key_permission(
+        1,
+        &system_server_ctx,
+        KeyPerm::Use,
+        &key,
+        &Some(key_perm_set![KeyPerm::GetInfo])
+    ));
+
+    Ok(())
+}
+
+#[test]
+fn check_key_permission_domain_selinux() -> Result<()> {
+    let (sctx, namespace, is_su) = check_context()?;
+    let key = KeyDescriptor {
+        domain: Domain::SELINUX,
+        nspace: namespace as i64,
+        alias: None,
+        blob: None,
+    };
+
+    assert!(check_key_permission(0, &sctx, KeyPerm::Use, &key, &None).is_ok());
+    assert!(check_key_permission(0, &sctx, KeyPerm::Delete, &key, &None).is_ok());
+    assert!(check_key_permission(0, &sctx, KeyPerm::GetInfo, &key, &None).is_ok());
+    assert!(check_key_permission(0, &sctx, KeyPerm::Rebind, &key, &None).is_ok());
+    assert!(check_key_permission(0, &sctx, KeyPerm::Update, &key, &None).is_ok());
+
+    if is_su {
+        assert!(check_key_permission(0, &sctx, KeyPerm::Grant, &key, &None).is_ok());
+        assert!(check_key_permission(0, &sctx, KeyPerm::ManageBlob, &key, &None).is_ok());
+        assert!(check_key_permission(0, &sctx, KeyPerm::UseDevId, &key, &None).is_ok());
+        assert!(check_key_permission(0, &sctx, KeyPerm::GenUniqueId, &key, &None).is_ok());
+        assert!(check_key_permission(0, &sctx, KeyPerm::ReqForcedOp, &key, &None).is_ok());
+    } else {
+        assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::Grant, &key, &None));
+        assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::ReqForcedOp, &key, &None));
+        assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::ManageBlob, &key, &None));
+        assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::UseDevId, &key, &None));
+        assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::GenUniqueId, &key, &None));
+    }
+    Ok(())
+}
+
+#[test]
+fn check_key_permission_domain_blob() -> Result<()> {
+    let (sctx, namespace, is_su) = check_context()?;
+    let key =
+        KeyDescriptor { domain: Domain::BLOB, nspace: namespace as i64, alias: None, blob: None };
+
+    if is_su {
+        check_key_permission(0, &sctx, KeyPerm::Use, &key, &None)
+    } else {
+        assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::Use, &key, &None));
+        Ok(())
+    }
+}
+
+#[test]
+fn check_key_permission_domain_key_id() -> Result<()> {
+    let key = KeyDescriptor { domain: Domain::KEY_ID, nspace: 0, alias: None, blob: None };
+
+    assert_eq!(
+        Some(&KsError::sys()),
+        check_key_permission(
+            0,
+            &selinux::Context::new("ignored").unwrap(),
+            KeyPerm::Use,
+            &key,
+            &None
+        )
+        .err()
+        .unwrap()
+        .root_cause()
+        .downcast_ref::<KsError>()
+    );
+    Ok(())
+}
+
+#[test]
+fn key_perm_set_all_test() {
+    let v = key_perm_set![
+        KeyPerm::ManageBlob,
+        KeyPerm::Delete,
+        KeyPerm::UseDevId,
+        KeyPerm::ReqForcedOp,
+        KeyPerm::GenUniqueId,
+        KeyPerm::Grant,
+        KeyPerm::GetInfo,
+        KeyPerm::Rebind,
+        KeyPerm::Update,
+        KeyPerm::Use // Test if the macro accepts missing comma at the end of the list.
+    ];
+    let mut i = v.into_iter();
+    assert_eq!(i.next().unwrap().name(), "delete");
+    assert_eq!(i.next().unwrap().name(), "gen_unique_id");
+    assert_eq!(i.next().unwrap().name(), "get_info");
+    assert_eq!(i.next().unwrap().name(), "grant");
+    assert_eq!(i.next().unwrap().name(), "manage_blob");
+    assert_eq!(i.next().unwrap().name(), "rebind");
+    assert_eq!(i.next().unwrap().name(), "req_forced_op");
+    assert_eq!(i.next().unwrap().name(), "update");
+    assert_eq!(i.next().unwrap().name(), "use");
+    assert_eq!(i.next().unwrap().name(), "use_dev_id");
+    assert_eq!(None, i.next());
+}
+#[test]
+fn key_perm_set_sparse_test() {
+    let v = key_perm_set![
+        KeyPerm::ManageBlob,
+        KeyPerm::ReqForcedOp,
+        KeyPerm::GenUniqueId,
+        KeyPerm::Update,
+        KeyPerm::Use, // Test if macro accepts the comma at the end of the list.
+    ];
+    let mut i = v.into_iter();
+    assert_eq!(i.next().unwrap().name(), "gen_unique_id");
+    assert_eq!(i.next().unwrap().name(), "manage_blob");
+    assert_eq!(i.next().unwrap().name(), "req_forced_op");
+    assert_eq!(i.next().unwrap().name(), "update");
+    assert_eq!(i.next().unwrap().name(), "use");
+    assert_eq!(None, i.next());
+}
+#[test]
+fn key_perm_set_empty_test() {
+    let v = key_perm_set![];
+    let mut i = v.into_iter();
+    assert_eq!(None, i.next());
+}
+#[test]
+fn key_perm_set_include_subset_test() {
+    let v1 = key_perm_set![
+        KeyPerm::ManageBlob,
+        KeyPerm::Delete,
+        KeyPerm::UseDevId,
+        KeyPerm::ReqForcedOp,
+        KeyPerm::GenUniqueId,
+        KeyPerm::Grant,
+        KeyPerm::GetInfo,
+        KeyPerm::Rebind,
+        KeyPerm::Update,
+        KeyPerm::Use,
+    ];
+    let v2 = key_perm_set![
+        KeyPerm::ManageBlob,
+        KeyPerm::Delete,
+        KeyPerm::Rebind,
+        KeyPerm::Update,
+        KeyPerm::Use,
+    ];
+    assert!(v1.includes(v2));
+    assert!(!v2.includes(v1));
+}
+#[test]
+fn key_perm_set_include_equal_test() {
+    let v1 = key_perm_set![
+        KeyPerm::ManageBlob,
+        KeyPerm::Delete,
+        KeyPerm::Rebind,
+        KeyPerm::Update,
+        KeyPerm::Use,
+    ];
+    let v2 = key_perm_set![
+        KeyPerm::ManageBlob,
+        KeyPerm::Delete,
+        KeyPerm::Rebind,
+        KeyPerm::Update,
+        KeyPerm::Use,
+    ];
+    assert!(v1.includes(v2));
+    assert!(v2.includes(v1));
+}
+#[test]
+fn key_perm_set_include_overlap_test() {
+    let v1 = key_perm_set![
+        KeyPerm::ManageBlob,
+        KeyPerm::Delete,
+        KeyPerm::Grant, // only in v1
+        KeyPerm::Rebind,
+        KeyPerm::Update,
+        KeyPerm::Use,
+    ];
+    let v2 = key_perm_set![
+        KeyPerm::ManageBlob,
+        KeyPerm::Delete,
+        KeyPerm::ReqForcedOp, // only in v2
+        KeyPerm::Rebind,
+        KeyPerm::Update,
+        KeyPerm::Use,
+    ];
+    assert!(!v1.includes(v2));
+    assert!(!v2.includes(v1));
+}
+#[test]
+fn key_perm_set_include_no_overlap_test() {
+    let v1 = key_perm_set![KeyPerm::ManageBlob, KeyPerm::Delete, KeyPerm::Grant,];
+    let v2 = key_perm_set![KeyPerm::ReqForcedOp, KeyPerm::Rebind, KeyPerm::Update, KeyPerm::Use,];
+    assert!(!v1.includes(v2));
+    assert!(!v2.includes(v1));
+}
diff --git a/keystore2/src/super_key.rs b/keystore2/src/super_key.rs
index 706a255..fa1de98 100644
--- a/keystore2/src/super_key.rs
+++ b/keystore2/src/super_key.rs
@@ -52,6 +52,9 @@
 };
 use std::{convert::TryFrom, ops::Deref};
 
+#[cfg(test)]
+mod tests;
+
 const MAX_MAX_BOOT_LEVEL: usize = 1_000_000_000;
 /// Allow up to 15 seconds between the user unlocking using a biometric, and the auth
 /// token being used to unlock in [`SuperKeyManager::try_unlock_user_with_biometric`].
@@ -1237,288 +1240,3 @@
         }
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::database::tests::make_bootlevel_key_entry;
-    use crate::database::tests::make_test_key_entry;
-    use crate::database::tests::new_test_db;
-    use rand::prelude::*;
-    const USER_ID: u32 = 0;
-    const TEST_KEY_ALIAS: &str = "TEST_KEY";
-    const TEST_BOOT_KEY_ALIAS: &str = "TEST_BOOT_KEY";
-
-    pub fn generate_password_blob() -> Password<'static> {
-        let mut rng = rand::thread_rng();
-        let mut password = vec![0u8; 64];
-        rng.fill_bytes(&mut password);
-
-        let mut zvec = ZVec::new(64).expect("Failed to create ZVec");
-        zvec[..].copy_from_slice(&password[..]);
-
-        Password::Owned(zvec)
-    }
-
-    fn setup_test(pw: &Password) -> (Arc<RwLock<SuperKeyManager>>, KeystoreDB, LegacyImporter) {
-        let mut keystore_db = new_test_db().unwrap();
-        let mut legacy_importer = LegacyImporter::new(Arc::new(Default::default()));
-        legacy_importer.set_empty();
-        let skm: Arc<RwLock<SuperKeyManager>> = Default::default();
-        assert!(skm
-            .write()
-            .unwrap()
-            .initialize_user(&mut keystore_db, &legacy_importer, USER_ID, pw, false)
-            .is_ok());
-        (skm, keystore_db, legacy_importer)
-    }
-
-    fn assert_unlocked(
-        skm: &Arc<RwLock<SuperKeyManager>>,
-        keystore_db: &mut KeystoreDB,
-        legacy_importer: &LegacyImporter,
-        user_id: u32,
-        err_msg: &str,
-    ) {
-        let user_state =
-            skm.write().unwrap().get_user_state(keystore_db, legacy_importer, user_id).unwrap();
-        match user_state {
-            UserState::AfterFirstUnlock(_) => {}
-            _ => panic!("{}", err_msg),
-        }
-    }
-
-    fn assert_locked(
-        skm: &Arc<RwLock<SuperKeyManager>>,
-        keystore_db: &mut KeystoreDB,
-        legacy_importer: &LegacyImporter,
-        user_id: u32,
-        err_msg: &str,
-    ) {
-        let user_state =
-            skm.write().unwrap().get_user_state(keystore_db, legacy_importer, user_id).unwrap();
-        match user_state {
-            UserState::BeforeFirstUnlock => {}
-            _ => panic!("{}", err_msg),
-        }
-    }
-
-    fn assert_uninitialized(
-        skm: &Arc<RwLock<SuperKeyManager>>,
-        keystore_db: &mut KeystoreDB,
-        legacy_importer: &LegacyImporter,
-        user_id: u32,
-        err_msg: &str,
-    ) {
-        let user_state =
-            skm.write().unwrap().get_user_state(keystore_db, legacy_importer, user_id).unwrap();
-        match user_state {
-            UserState::Uninitialized => {}
-            _ => panic!("{}", err_msg),
-        }
-    }
-
-    #[test]
-    fn test_initialize_user() {
-        let pw: Password = generate_password_blob();
-        let (skm, mut keystore_db, legacy_importer) = setup_test(&pw);
-        assert_unlocked(
-            &skm,
-            &mut keystore_db,
-            &legacy_importer,
-            USER_ID,
-            "The user was not unlocked after initialization!",
-        );
-    }
-
-    #[test]
-    fn test_unlock_user() {
-        let pw: Password = generate_password_blob();
-        let (skm, mut keystore_db, legacy_importer) = setup_test(&pw);
-        assert_unlocked(
-            &skm,
-            &mut keystore_db,
-            &legacy_importer,
-            USER_ID,
-            "The user was not unlocked after initialization!",
-        );
-
-        skm.write().unwrap().data.user_keys.clear();
-        assert_locked(
-            &skm,
-            &mut keystore_db,
-            &legacy_importer,
-            USER_ID,
-            "Clearing the cache did not lock the user!",
-        );
-
-        assert!(skm
-            .write()
-            .unwrap()
-            .unlock_user(&mut keystore_db, &legacy_importer, USER_ID, &pw)
-            .is_ok());
-        assert_unlocked(
-            &skm,
-            &mut keystore_db,
-            &legacy_importer,
-            USER_ID,
-            "The user did not unlock!",
-        );
-    }
-
-    #[test]
-    fn test_unlock_wrong_password() {
-        let pw: Password = generate_password_blob();
-        let wrong_pw: Password = generate_password_blob();
-        let (skm, mut keystore_db, legacy_importer) = setup_test(&pw);
-        assert_unlocked(
-            &skm,
-            &mut keystore_db,
-            &legacy_importer,
-            USER_ID,
-            "The user was not unlocked after initialization!",
-        );
-
-        skm.write().unwrap().data.user_keys.clear();
-        assert_locked(
-            &skm,
-            &mut keystore_db,
-            &legacy_importer,
-            USER_ID,
-            "Clearing the cache did not lock the user!",
-        );
-
-        assert!(skm
-            .write()
-            .unwrap()
-            .unlock_user(&mut keystore_db, &legacy_importer, USER_ID, &wrong_pw)
-            .is_err());
-        assert_locked(
-            &skm,
-            &mut keystore_db,
-            &legacy_importer,
-            USER_ID,
-            "The user was unlocked with an incorrect password!",
-        );
-    }
-
-    #[test]
-    fn test_unlock_user_idempotent() {
-        let pw: Password = generate_password_blob();
-        let (skm, mut keystore_db, legacy_importer) = setup_test(&pw);
-        assert_unlocked(
-            &skm,
-            &mut keystore_db,
-            &legacy_importer,
-            USER_ID,
-            "The user was not unlocked after initialization!",
-        );
-
-        skm.write().unwrap().data.user_keys.clear();
-        assert_locked(
-            &skm,
-            &mut keystore_db,
-            &legacy_importer,
-            USER_ID,
-            "Clearing the cache did not lock the user!",
-        );
-
-        for _ in 0..5 {
-            assert!(skm
-                .write()
-                .unwrap()
-                .unlock_user(&mut keystore_db, &legacy_importer, USER_ID, &pw)
-                .is_ok());
-            assert_unlocked(
-                &skm,
-                &mut keystore_db,
-                &legacy_importer,
-                USER_ID,
-                "The user did not unlock!",
-            );
-        }
-    }
-
-    fn test_user_removal(locked: bool) {
-        let pw: Password = generate_password_blob();
-        let (skm, mut keystore_db, legacy_importer) = setup_test(&pw);
-        assert_unlocked(
-            &skm,
-            &mut keystore_db,
-            &legacy_importer,
-            USER_ID,
-            "The user was not unlocked after initialization!",
-        );
-
-        assert!(make_test_key_entry(
-            &mut keystore_db,
-            Domain::APP,
-            USER_ID.into(),
-            TEST_KEY_ALIAS,
-            None
-        )
-        .is_ok());
-        assert!(make_bootlevel_key_entry(
-            &mut keystore_db,
-            Domain::APP,
-            USER_ID.into(),
-            TEST_BOOT_KEY_ALIAS,
-            false
-        )
-        .is_ok());
-
-        assert!(keystore_db
-            .key_exists(Domain::APP, USER_ID.into(), TEST_KEY_ALIAS, KeyType::Client)
-            .unwrap());
-        assert!(keystore_db
-            .key_exists(Domain::APP, USER_ID.into(), TEST_BOOT_KEY_ALIAS, KeyType::Client)
-            .unwrap());
-
-        if locked {
-            skm.write().unwrap().data.user_keys.clear();
-            assert_locked(
-                &skm,
-                &mut keystore_db,
-                &legacy_importer,
-                USER_ID,
-                "Clearing the cache did not lock the user!",
-            );
-        }
-
-        assert!(skm
-            .write()
-            .unwrap()
-            .remove_user(&mut keystore_db, &legacy_importer, USER_ID)
-            .is_ok());
-        assert_uninitialized(
-            &skm,
-            &mut keystore_db,
-            &legacy_importer,
-            USER_ID,
-            "The user was not removed!",
-        );
-
-        assert!(!skm
-            .write()
-            .unwrap()
-            .super_key_exists_in_db_for_user(&mut keystore_db, &legacy_importer, USER_ID)
-            .unwrap());
-
-        assert!(!keystore_db
-            .key_exists(Domain::APP, USER_ID.into(), TEST_KEY_ALIAS, KeyType::Client)
-            .unwrap());
-        assert!(!keystore_db
-            .key_exists(Domain::APP, USER_ID.into(), TEST_BOOT_KEY_ALIAS, KeyType::Client)
-            .unwrap());
-    }
-
-    #[test]
-    fn test_remove_unlocked_user() {
-        test_user_removal(false);
-    }
-
-    #[test]
-    fn test_remove_locked_user() {
-        test_user_removal(true);
-    }
-}
diff --git a/keystore2/src/super_key/tests.rs b/keystore2/src/super_key/tests.rs
new file mode 100644
index 0000000..76a96a7
--- /dev/null
+++ b/keystore2/src/super_key/tests.rs
@@ -0,0 +1,287 @@
+// 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.
+
+//! Super-key tests.
+
+use super::*;
+use crate::database::tests::make_bootlevel_key_entry;
+use crate::database::tests::make_test_key_entry;
+use crate::database::tests::new_test_db;
+use rand::prelude::*;
+const USER_ID: u32 = 0;
+const TEST_KEY_ALIAS: &str = "TEST_KEY";
+const TEST_BOOT_KEY_ALIAS: &str = "TEST_BOOT_KEY";
+
+pub fn generate_password_blob() -> Password<'static> {
+    let mut rng = rand::thread_rng();
+    let mut password = vec![0u8; 64];
+    rng.fill_bytes(&mut password);
+
+    let mut zvec = ZVec::new(64).expect("Failed to create ZVec");
+    zvec[..].copy_from_slice(&password[..]);
+
+    Password::Owned(zvec)
+}
+
+fn setup_test(pw: &Password) -> (Arc<RwLock<SuperKeyManager>>, KeystoreDB, LegacyImporter) {
+    let mut keystore_db = new_test_db().unwrap();
+    let mut legacy_importer = LegacyImporter::new(Arc::new(Default::default()));
+    legacy_importer.set_empty();
+    let skm: Arc<RwLock<SuperKeyManager>> = Default::default();
+    assert!(skm
+        .write()
+        .unwrap()
+        .initialize_user(&mut keystore_db, &legacy_importer, USER_ID, pw, false)
+        .is_ok());
+    (skm, keystore_db, legacy_importer)
+}
+
+fn assert_unlocked(
+    skm: &Arc<RwLock<SuperKeyManager>>,
+    keystore_db: &mut KeystoreDB,
+    legacy_importer: &LegacyImporter,
+    user_id: u32,
+    err_msg: &str,
+) {
+    let user_state =
+        skm.write().unwrap().get_user_state(keystore_db, legacy_importer, user_id).unwrap();
+    match user_state {
+        UserState::AfterFirstUnlock(_) => {}
+        _ => panic!("{}", err_msg),
+    }
+}
+
+fn assert_locked(
+    skm: &Arc<RwLock<SuperKeyManager>>,
+    keystore_db: &mut KeystoreDB,
+    legacy_importer: &LegacyImporter,
+    user_id: u32,
+    err_msg: &str,
+) {
+    let user_state =
+        skm.write().unwrap().get_user_state(keystore_db, legacy_importer, user_id).unwrap();
+    match user_state {
+        UserState::BeforeFirstUnlock => {}
+        _ => panic!("{}", err_msg),
+    }
+}
+
+fn assert_uninitialized(
+    skm: &Arc<RwLock<SuperKeyManager>>,
+    keystore_db: &mut KeystoreDB,
+    legacy_importer: &LegacyImporter,
+    user_id: u32,
+    err_msg: &str,
+) {
+    let user_state =
+        skm.write().unwrap().get_user_state(keystore_db, legacy_importer, user_id).unwrap();
+    match user_state {
+        UserState::Uninitialized => {}
+        _ => panic!("{}", err_msg),
+    }
+}
+
+#[test]
+fn test_initialize_user() {
+    let pw: Password = generate_password_blob();
+    let (skm, mut keystore_db, legacy_importer) = setup_test(&pw);
+    assert_unlocked(
+        &skm,
+        &mut keystore_db,
+        &legacy_importer,
+        USER_ID,
+        "The user was not unlocked after initialization!",
+    );
+}
+
+#[test]
+fn test_unlock_user() {
+    let pw: Password = generate_password_blob();
+    let (skm, mut keystore_db, legacy_importer) = setup_test(&pw);
+    assert_unlocked(
+        &skm,
+        &mut keystore_db,
+        &legacy_importer,
+        USER_ID,
+        "The user was not unlocked after initialization!",
+    );
+
+    skm.write().unwrap().data.user_keys.clear();
+    assert_locked(
+        &skm,
+        &mut keystore_db,
+        &legacy_importer,
+        USER_ID,
+        "Clearing the cache did not lock the user!",
+    );
+
+    assert!(skm
+        .write()
+        .unwrap()
+        .unlock_user(&mut keystore_db, &legacy_importer, USER_ID, &pw)
+        .is_ok());
+    assert_unlocked(&skm, &mut keystore_db, &legacy_importer, USER_ID, "The user did not unlock!");
+}
+
+#[test]
+fn test_unlock_wrong_password() {
+    let pw: Password = generate_password_blob();
+    let wrong_pw: Password = generate_password_blob();
+    let (skm, mut keystore_db, legacy_importer) = setup_test(&pw);
+    assert_unlocked(
+        &skm,
+        &mut keystore_db,
+        &legacy_importer,
+        USER_ID,
+        "The user was not unlocked after initialization!",
+    );
+
+    skm.write().unwrap().data.user_keys.clear();
+    assert_locked(
+        &skm,
+        &mut keystore_db,
+        &legacy_importer,
+        USER_ID,
+        "Clearing the cache did not lock the user!",
+    );
+
+    assert!(skm
+        .write()
+        .unwrap()
+        .unlock_user(&mut keystore_db, &legacy_importer, USER_ID, &wrong_pw)
+        .is_err());
+    assert_locked(
+        &skm,
+        &mut keystore_db,
+        &legacy_importer,
+        USER_ID,
+        "The user was unlocked with an incorrect password!",
+    );
+}
+
+#[test]
+fn test_unlock_user_idempotent() {
+    let pw: Password = generate_password_blob();
+    let (skm, mut keystore_db, legacy_importer) = setup_test(&pw);
+    assert_unlocked(
+        &skm,
+        &mut keystore_db,
+        &legacy_importer,
+        USER_ID,
+        "The user was not unlocked after initialization!",
+    );
+
+    skm.write().unwrap().data.user_keys.clear();
+    assert_locked(
+        &skm,
+        &mut keystore_db,
+        &legacy_importer,
+        USER_ID,
+        "Clearing the cache did not lock the user!",
+    );
+
+    for _ in 0..5 {
+        assert!(skm
+            .write()
+            .unwrap()
+            .unlock_user(&mut keystore_db, &legacy_importer, USER_ID, &pw)
+            .is_ok());
+        assert_unlocked(
+            &skm,
+            &mut keystore_db,
+            &legacy_importer,
+            USER_ID,
+            "The user did not unlock!",
+        );
+    }
+}
+
+fn test_user_removal(locked: bool) {
+    let pw: Password = generate_password_blob();
+    let (skm, mut keystore_db, legacy_importer) = setup_test(&pw);
+    assert_unlocked(
+        &skm,
+        &mut keystore_db,
+        &legacy_importer,
+        USER_ID,
+        "The user was not unlocked after initialization!",
+    );
+
+    assert!(make_test_key_entry(
+        &mut keystore_db,
+        Domain::APP,
+        USER_ID.into(),
+        TEST_KEY_ALIAS,
+        None
+    )
+    .is_ok());
+    assert!(make_bootlevel_key_entry(
+        &mut keystore_db,
+        Domain::APP,
+        USER_ID.into(),
+        TEST_BOOT_KEY_ALIAS,
+        false
+    )
+    .is_ok());
+
+    assert!(keystore_db
+        .key_exists(Domain::APP, USER_ID.into(), TEST_KEY_ALIAS, KeyType::Client)
+        .unwrap());
+    assert!(keystore_db
+        .key_exists(Domain::APP, USER_ID.into(), TEST_BOOT_KEY_ALIAS, KeyType::Client)
+        .unwrap());
+
+    if locked {
+        skm.write().unwrap().data.user_keys.clear();
+        assert_locked(
+            &skm,
+            &mut keystore_db,
+            &legacy_importer,
+            USER_ID,
+            "Clearing the cache did not lock the user!",
+        );
+    }
+
+    assert!(skm.write().unwrap().remove_user(&mut keystore_db, &legacy_importer, USER_ID).is_ok());
+    assert_uninitialized(
+        &skm,
+        &mut keystore_db,
+        &legacy_importer,
+        USER_ID,
+        "The user was not removed!",
+    );
+
+    assert!(!skm
+        .write()
+        .unwrap()
+        .super_key_exists_in_db_for_user(&mut keystore_db, &legacy_importer, USER_ID)
+        .unwrap());
+
+    assert!(!keystore_db
+        .key_exists(Domain::APP, USER_ID.into(), TEST_KEY_ALIAS, KeyType::Client)
+        .unwrap());
+    assert!(!keystore_db
+        .key_exists(Domain::APP, USER_ID.into(), TEST_BOOT_KEY_ALIAS, KeyType::Client)
+        .unwrap());
+}
+
+#[test]
+fn test_remove_unlocked_user() {
+    test_user_removal(false);
+}
+
+#[test]
+fn test_remove_locked_user() {
+    test_user_removal(true);
+}
diff --git a/keystore2/src/sw_keyblob.rs b/keystore2/src/sw_keyblob.rs
index 47ab49f..c0173b5 100644
--- a/keystore2/src/sw_keyblob.rs
+++ b/keystore2/src/sw_keyblob.rs
@@ -28,6 +28,9 @@
 use keystore2_crypto::hmac_sha256;
 use std::mem::size_of;
 
+#[cfg(test)]
+mod tests;
+
 /// Root of trust value.
 const SOFTWARE_ROOT_OF_TRUST: &[u8] = b"SW";
 
@@ -556,481 +559,3 @@
         .clone_from_slice(&serialized_size.to_ne_bytes());
     Ok(result)
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
-        Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
-        KeyOrigin::KeyOrigin, KeyParameter::KeyParameter,
-        KeyParameterValue::KeyParameterValue as KPV, KeyPurpose::KeyPurpose,
-        PaddingMode::PaddingMode, Tag::Tag,
-    };
-
-    macro_rules! expect_err {
-        ($result:expr, $err_msg:expr) => {
-            assert!(
-                $result.is_err(),
-                "Expected error containing '{}', got success {:?}",
-                $err_msg,
-                $result
-            );
-            let err = $result.err();
-            assert!(
-                format!("{:?}", err).contains($err_msg),
-                "Unexpected error {:?}, doesn't contain '{}'",
-                err,
-                $err_msg
-            );
-        };
-    }
-
-    #[test]
-    fn test_consume_u8() {
-        let buffer = [1, 2];
-        let mut data = &buffer[..];
-        assert_eq!(1u8, consume_u8(&mut data).unwrap());
-        assert_eq!(2u8, consume_u8(&mut data).unwrap());
-        let result = consume_u8(&mut data);
-        expect_err!(result, "failed to find 1 byte");
-    }
-
-    #[test]
-    fn test_consume_u32() {
-        // All supported platforms are little-endian.
-        let buffer = [
-            0x01, 0x02, 0x03, 0x04, // little-endian u32
-            0x04, 0x03, 0x02, 0x01, // little-endian u32
-            0x11, 0x12, 0x13,
-        ];
-        let mut data = &buffer[..];
-        assert_eq!(0x04030201u32, consume_u32(&mut data).unwrap());
-        assert_eq!(0x01020304u32, consume_u32(&mut data).unwrap());
-        let result = consume_u32(&mut data);
-        expect_err!(result, "failed to find 4 bytes");
-    }
-
-    #[test]
-    fn test_consume_i64() {
-        // All supported platforms are little-endian.
-        let buffer = [
-            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // little-endian i64
-            0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, // little-endian i64
-            0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-        ];
-        let mut data = &buffer[..];
-        assert_eq!(0x0807060504030201i64, consume_i64(&mut data).unwrap());
-        assert_eq!(0x0102030405060708i64, consume_i64(&mut data).unwrap());
-        let result = consume_i64(&mut data);
-        expect_err!(result, "failed to find 8 bytes");
-    }
-
-    #[test]
-    fn test_consume_vec() {
-        let buffer = [
-            0x01, 0x00, 0x00, 0x00, 0xaa, //
-            0x00, 0x00, 0x00, 0x00, //
-            0x01, 0x00, 0x00, 0x00, 0xbb, //
-            0x07, 0x00, 0x00, 0x00, 0xbb, // not enough data
-        ];
-        let mut data = &buffer[..];
-        assert_eq!(vec![0xaa], consume_vec(&mut data).unwrap());
-        assert_eq!(Vec::<u8>::new(), consume_vec(&mut data).unwrap());
-        assert_eq!(vec![0xbb], consume_vec(&mut data).unwrap());
-        let result = consume_vec(&mut data);
-        expect_err!(result, "failed to find 7 bytes");
-
-        let buffer = [
-            0x01, 0x00, 0x00, //
-        ];
-        let mut data = &buffer[..];
-        let result = consume_vec(&mut data);
-        expect_err!(result, "failed to find 4 bytes");
-    }
-
-    #[test]
-    fn test_key_new_from_serialized() {
-        let hidden = hidden_params(&[], &[SOFTWARE_ROOT_OF_TRUST]);
-        // Test data originally generated by instrumenting Cuttlefish C++ KeyMint while running VTS
-        // tests.
-        let tests = [
-            (
-                concat!(
-                    "0010000000d43c2f04f948521b81bdbf001310f5920000000000000000000000",
-                    "00000000000c0000006400000002000010200000000300003080000000010000",
-                    "2000000000010000200100000004000020020000000600002001000000be0200",
-                    "1000000000c1020030b0ad0100c20200307b150300bd020060a8bb52407b0100",
-                    "00ce02003011643401cf020030000000003b06b13ae6ae6671",
-                ),
-                KeyBlob {
-                    key_material: hex::decode("d43c2f04f948521b81bdbf001310f592").unwrap(),
-                    hw_enforced: vec![],
-                    sw_enforced: vec![
-                        KeyParameter { tag: Tag::ALGORITHM, value: KPV::Algorithm(Algorithm::AES) },
-                        KeyParameter { tag: Tag::KEY_SIZE, value: KPV::Integer(128) },
-                        KeyParameter {
-                            tag: Tag::PURPOSE,
-                            value: KPV::KeyPurpose(KeyPurpose::ENCRYPT),
-                        },
-                        KeyParameter {
-                            tag: Tag::PURPOSE,
-                            value: KPV::KeyPurpose(KeyPurpose::DECRYPT),
-                        },
-                        KeyParameter {
-                            tag: Tag::BLOCK_MODE,
-                            value: KPV::BlockMode(BlockMode::CBC),
-                        },
-                        KeyParameter {
-                            tag: Tag::PADDING,
-                            value: KPV::PaddingMode(PaddingMode::NONE),
-                        },
-                        KeyParameter { tag: Tag::ORIGIN, value: KPV::Origin(KeyOrigin::GENERATED) },
-                        KeyParameter { tag: Tag::OS_VERSION, value: KPV::Integer(110000) },
-                        KeyParameter { tag: Tag::OS_PATCHLEVEL, value: KPV::Integer(202107) },
-                        KeyParameter {
-                            tag: Tag::CREATION_DATETIME,
-                            value: KPV::DateTime(1628871769000),
-                        },
-                        KeyParameter { tag: Tag::VENDOR_PATCHLEVEL, value: KPV::Integer(20210705) },
-                        KeyParameter { tag: Tag::BOOT_PATCHLEVEL, value: KPV::Integer(0) },
-                    ],
-                },
-                Some(KeyFormat::RAW),
-            ),
-            (
-                concat!(
-                    "00df0000003081dc020101044200b6ce876b947e263d61b8e3998d50dc0afb6b",
-                    "a14e46ab7ca532fbe2a379b155d0a5bb99265402857b1601fb20be6c244bf654",
-                    "e9e79413cd503eae3d9cf68ed24f47a00706052b81040023a181890381860004",
-                    "006b840f0db0b12f074ab916c7773cfa7d42967c9e5b4fae09cf999f7e116d14",
-                    "0743bdd028db0a3fcc670e721b9f00bc7fb70aa401c7d6de6582fc26962a29b7",
-                    "45e30142e90685646661550344113aaf28bdee6cb02d19df1faab4398556a909",
-                    "7d6f64b95209601a549389a311231c6cce78354f2cdbc3a904abf70686f5f0c3",
-                    "b877984d000000000000000000000000000000000c0000006400000002000010",
-                    "030000000a000010030000000100002002000000010000200300000005000020",
-                    "000000000300003009020000be02001000000000c1020030b0ad0100c2020030",
-                    "7b150300bd02006018d352407b010000ce02003011643401cf02003000000000",
-                    "2f69002e55e9b0a3"
-                ),
-                KeyBlob {
-                    key_material: hex::decode(concat!(
-                        "3081dc020101044200b6ce876b947e263d61b8e3998d50dc0afb6ba14e46ab7c",
-                        "a532fbe2a379b155d0a5bb99265402857b1601fb20be6c244bf654e9e79413cd",
-                        "503eae3d9cf68ed24f47a00706052b81040023a181890381860004006b840f0d",
-                        "b0b12f074ab916c7773cfa7d42967c9e5b4fae09cf999f7e116d140743bdd028",
-                        "db0a3fcc670e721b9f00bc7fb70aa401c7d6de6582fc26962a29b745e30142e9",
-                        "0685646661550344113aaf28bdee6cb02d19df1faab4398556a9097d6f64b952",
-                        "09601a549389a311231c6cce78354f2cdbc3a904abf70686f5f0c3b877984d",
-                    ))
-                    .unwrap(),
-                    hw_enforced: vec![],
-                    sw_enforced: vec![
-                        KeyParameter { tag: Tag::ALGORITHM, value: KPV::Algorithm(Algorithm::EC) },
-                        KeyParameter { tag: Tag::EC_CURVE, value: KPV::EcCurve(EcCurve::P_521) },
-                        KeyParameter {
-                            tag: Tag::PURPOSE,
-                            value: KPV::KeyPurpose(KeyPurpose::SIGN),
-                        },
-                        KeyParameter {
-                            tag: Tag::PURPOSE,
-                            value: KPV::KeyPurpose(KeyPurpose::VERIFY),
-                        },
-                        KeyParameter { tag: Tag::DIGEST, value: KPV::Digest(Digest::NONE) },
-                        KeyParameter { tag: Tag::KEY_SIZE, value: KPV::Integer(521) },
-                        KeyParameter { tag: Tag::ORIGIN, value: KPV::Origin(KeyOrigin::GENERATED) },
-                        KeyParameter { tag: Tag::OS_VERSION, value: KPV::Integer(110000) },
-                        KeyParameter { tag: Tag::OS_PATCHLEVEL, value: KPV::Integer(202107) },
-                        KeyParameter {
-                            tag: Tag::CREATION_DATETIME,
-                            value: KPV::DateTime(1628871775000),
-                        },
-                        KeyParameter { tag: Tag::VENDOR_PATCHLEVEL, value: KPV::Integer(20210705) },
-                        KeyParameter { tag: Tag::BOOT_PATCHLEVEL, value: KPV::Integer(0) },
-                    ],
-                },
-                Some(KeyFormat::PKCS8),
-            ),
-            (
-                concat!(
-                    "0037000000541d4c440223650d5f51753c1abd80c725034485551e874d62327c",
-                    "65f6247a057f1218bd6c8cd7d319103ddb823fc11fb6c2c7268b5acc00000000",
-                    "0000000000000000000000000c00000064000000020000108000000003000030",
-                    "b801000001000020020000000100002003000000050000200400000008000030",
-                    "00010000be02001000000000c1020030b0ad0100c20200307b150300bd020060",
-                    "00d752407b010000ce02003011643401cf0200300000000036e6986ffc45fbb0",
-                ),
-                KeyBlob {
-                    key_material: hex::decode(concat!(
-                        "541d4c440223650d5f51753c1abd80c725034485551e874d62327c65f6247a05",
-                        "7f1218bd6c8cd7d319103ddb823fc11fb6c2c7268b5acc"
-                    ))
-                    .unwrap(),
-                    hw_enforced: vec![],
-                    sw_enforced: vec![
-                        KeyParameter {
-                            tag: Tag::ALGORITHM,
-                            value: KPV::Algorithm(Algorithm::HMAC),
-                        },
-                        KeyParameter { tag: Tag::KEY_SIZE, value: KPV::Integer(440) },
-                        KeyParameter {
-                            tag: Tag::PURPOSE,
-                            value: KPV::KeyPurpose(KeyPurpose::SIGN),
-                        },
-                        KeyParameter {
-                            tag: Tag::PURPOSE,
-                            value: KPV::KeyPurpose(KeyPurpose::VERIFY),
-                        },
-                        KeyParameter { tag: Tag::DIGEST, value: KPV::Digest(Digest::SHA_2_256) },
-                        KeyParameter { tag: Tag::MIN_MAC_LENGTH, value: KPV::Integer(256) },
-                        KeyParameter { tag: Tag::ORIGIN, value: KPV::Origin(KeyOrigin::GENERATED) },
-                        KeyParameter { tag: Tag::OS_VERSION, value: KPV::Integer(110000) },
-                        KeyParameter { tag: Tag::OS_PATCHLEVEL, value: KPV::Integer(202107) },
-                        KeyParameter {
-                            tag: Tag::CREATION_DATETIME,
-                            value: KPV::DateTime(1628871776000),
-                        },
-                        KeyParameter { tag: Tag::VENDOR_PATCHLEVEL, value: KPV::Integer(20210705) },
-                        KeyParameter { tag: Tag::BOOT_PATCHLEVEL, value: KPV::Integer(0) },
-                    ],
-                },
-                Some(KeyFormat::RAW),
-            ),
-            (
-                concat!(
-                    "00a8040000308204a40201000282010100bc47b5c71116766669b91fa747df87",
-                    "a1963df83956569d4ac232aeba8a246c0ec73bf606374a6d07f30c2162f97082",
-                    "825c7c6e482a2841dfeaec1429d84e52c54a6b2f760dec952c9c44a3c3a80f31",
-                    "c1ced84878edd4858059071c4d20d9ab0aae978bd68c1eb448e174a9736c3973",
-                    "6838151642eda8215107375865a99a57f29467c74c40f37b0221b93ec3f4f22d",
-                    "5337c8bf9245d56936196a92b1dea315ecce8785f9fa9b7d159ca207612cc0de",
-                    "b0957d61dbba5d9bd38784f4fecbf233b04e686a340528665ecd03db8e8a09b2",
-                    "540c84e45c4a99fb338b76bba7722856b5113341c349708937228f167d238ed8",
-                    "efb9cc19547dd620f6a90d95f07e50bfe102030100010282010002f91b69d9af",
-                    "59fe87421af9ba60f15c77f9c1c90effd6634332876f8ee5a116b126f55d3703",
-                    "8bf9f588ae20c8d951d842e35c9ef35a7822d3ebf72c0b7c3e229b289ae2e178",
-                    "a848e06d558c2e03d26871ee98a35f370d461ff1c4acc39d684de680a25ec88e",
-                    "e610260e406c400bdeb2893b2d0330cb483e662fa5abd24c2b82143e85dfe30a",
-                    "e7a31f8262da2903d882b35a34a26b699ff2d812bad4b126a0065ec0e101d73a",
-                    "e6f8b29a9144eb83f54940a371fc7416c2c0370df6a41cb5391f17ba33239e1b",
-                    "4217c8db50db5c6bf77ccf621354ecc652a4f7196054c254566fd7b3bc0f3817",
-                    "d9380b190bd382aaffa37785759f285194c11a188bccde0e2e2902818100fb23",
-                    "3335770c9f3cbd4b6ede5f12d03c449b1997bce06a8249bc3de99972fd0d0a63",
-                    "3f7790d1011bf5eedee16fa45a9107a910656ecaee364ce9edb4369843be71f2",
-                    "7a74852d6c7215a6cc60d9803bcac544922f806d8e5844e0ddd914bd78009490",
-                    "4c2856d2b944fade3fb1d67d4a33fb7663a9ab660ab372c2e4868a0f45990281",
-                    "8100bfecf2bb4012e880fd065a0b088f2d757af2878d3f1305f21ce7a7158458",
-                    "18e01181ff06b2f406239fc50808ce3dbe7b68ec01174913c0f237feb3c8c7eb",
-                    "0078b77fb5b8f214b72f6d3835b1a7ebe8b132feb6cb34ab09ce22b98160fc84",
-                    "20fcbf48d1eee49f874e902f049b206a61a095f0405a4935e7c5e49757ab7b57",
-                    "298902818100ec0049383e16f3716de5fc5b2677148efe5dceb02483b43399bd",
-                    "3765559994a9f3900eed7a7e9e8f3b0eee0e660eca392e3cb736cae612f39e55",
-                    "dad696d3821def10d1f8bbca52f5e6d8e7893ffbdcb491aafdc17bebf86f84d2",
-                    "d8480ed07a7bf9209d20ef6e79429489d4cb7768281a2f7e32ec1830fd6f6332",
-                    "38f521ba764902818100b2c3ce5751580b4e51df3fb175387f5c24b79040a4d6",
-                    "603c6265f70018b441ff3aef7d8e4cd2f480ec0906f1c4c0481304e8861f9d46",
-                    "93fa48e3a9abc362859eeb343e1c5507ac94b5439ce7ac04154a2fb886a4819b",
-                    "2a57e18a2e131b412ac4a09b004766959cdf357745f003e272aab3de02e2d5bc",
-                    "2af4ed75760858ab181902818061d19c2a8dcacde104b97f7c4fae11216157c1",
-                    "c0a258d882984d12383a73dc56fe2ac93512bb321df9706ecdb2f70a44c949c4",
-                    "340a9fae64a0646cf51f37c58c08bebde91667b3b2fa7c895f7983d4786c5526",
-                    "1941b3654533b0598383ebbcffcdf28b6cf13d376e3a70b49b14d8d06e8563a2",
-                    "47f56a337e3b9845b4f2b61356000000000000000000000000000000000d0000",
-                    "007000000002000010010000000300003000080000c800005001000100000000",
-                    "0001000020020000000100002003000000050000200000000006000020010000",
-                    "00be02001000000000c1020030b0ad0100c20200307b150300bd020060a8bb52",
-                    "407b010000ce02003011643401cf02003000000000544862e9c961e857",
-                ),
-                KeyBlob {
-                    key_material: hex::decode(concat!(
-                        "308204a40201000282010100bc47b5c71116766669b91fa747df87a1963df839",
-                        "56569d4ac232aeba8a246c0ec73bf606374a6d07f30c2162f97082825c7c6e48",
-                        "2a2841dfeaec1429d84e52c54a6b2f760dec952c9c44a3c3a80f31c1ced84878",
-                        "edd4858059071c4d20d9ab0aae978bd68c1eb448e174a9736c39736838151642",
-                        "eda8215107375865a99a57f29467c74c40f37b0221b93ec3f4f22d5337c8bf92",
-                        "45d56936196a92b1dea315ecce8785f9fa9b7d159ca207612cc0deb0957d61db",
-                        "ba5d9bd38784f4fecbf233b04e686a340528665ecd03db8e8a09b2540c84e45c",
-                        "4a99fb338b76bba7722856b5113341c349708937228f167d238ed8efb9cc1954",
-                        "7dd620f6a90d95f07e50bfe102030100010282010002f91b69d9af59fe87421a",
-                        "f9ba60f15c77f9c1c90effd6634332876f8ee5a116b126f55d37038bf9f588ae",
-                        "20c8d951d842e35c9ef35a7822d3ebf72c0b7c3e229b289ae2e178a848e06d55",
-                        "8c2e03d26871ee98a35f370d461ff1c4acc39d684de680a25ec88ee610260e40",
-                        "6c400bdeb2893b2d0330cb483e662fa5abd24c2b82143e85dfe30ae7a31f8262",
-                        "da2903d882b35a34a26b699ff2d812bad4b126a0065ec0e101d73ae6f8b29a91",
-                        "44eb83f54940a371fc7416c2c0370df6a41cb5391f17ba33239e1b4217c8db50",
-                        "db5c6bf77ccf621354ecc652a4f7196054c254566fd7b3bc0f3817d9380b190b",
-                        "d382aaffa37785759f285194c11a188bccde0e2e2902818100fb233335770c9f",
-                        "3cbd4b6ede5f12d03c449b1997bce06a8249bc3de99972fd0d0a633f7790d101",
-                        "1bf5eedee16fa45a9107a910656ecaee364ce9edb4369843be71f27a74852d6c",
-                        "7215a6cc60d9803bcac544922f806d8e5844e0ddd914bd780094904c2856d2b9",
-                        "44fade3fb1d67d4a33fb7663a9ab660ab372c2e4868a0f459902818100bfecf2",
-                        "bb4012e880fd065a0b088f2d757af2878d3f1305f21ce7a715845818e01181ff",
-                        "06b2f406239fc50808ce3dbe7b68ec01174913c0f237feb3c8c7eb0078b77fb5",
-                        "b8f214b72f6d3835b1a7ebe8b132feb6cb34ab09ce22b98160fc8420fcbf48d1",
-                        "eee49f874e902f049b206a61a095f0405a4935e7c5e49757ab7b572989028181",
-                        "00ec0049383e16f3716de5fc5b2677148efe5dceb02483b43399bd3765559994",
-                        "a9f3900eed7a7e9e8f3b0eee0e660eca392e3cb736cae612f39e55dad696d382",
-                        "1def10d1f8bbca52f5e6d8e7893ffbdcb491aafdc17bebf86f84d2d8480ed07a",
-                        "7bf9209d20ef6e79429489d4cb7768281a2f7e32ec1830fd6f633238f521ba76",
-                        "4902818100b2c3ce5751580b4e51df3fb175387f5c24b79040a4d6603c6265f7",
-                        "0018b441ff3aef7d8e4cd2f480ec0906f1c4c0481304e8861f9d4693fa48e3a9",
-                        "abc362859eeb343e1c5507ac94b5439ce7ac04154a2fb886a4819b2a57e18a2e",
-                        "131b412ac4a09b004766959cdf357745f003e272aab3de02e2d5bc2af4ed7576",
-                        "0858ab181902818061d19c2a8dcacde104b97f7c4fae11216157c1c0a258d882",
-                        "984d12383a73dc56fe2ac93512bb321df9706ecdb2f70a44c949c4340a9fae64",
-                        "a0646cf51f37c58c08bebde91667b3b2fa7c895f7983d4786c55261941b36545",
-                        "33b0598383ebbcffcdf28b6cf13d376e3a70b49b14d8d06e8563a247f56a337e",
-                        "3b9845b4f2b61356",
-                    ))
-                    .unwrap(),
-                    hw_enforced: vec![],
-                    sw_enforced: vec![
-                        KeyParameter { tag: Tag::ALGORITHM, value: KPV::Algorithm(Algorithm::RSA) },
-                        KeyParameter { tag: Tag::KEY_SIZE, value: KPV::Integer(2048) },
-                        KeyParameter {
-                            tag: Tag::RSA_PUBLIC_EXPONENT,
-                            value: KPV::LongInteger(65537),
-                        },
-                        KeyParameter {
-                            tag: Tag::PURPOSE,
-                            value: KPV::KeyPurpose(KeyPurpose::SIGN),
-                        },
-                        KeyParameter {
-                            tag: Tag::PURPOSE,
-                            value: KPV::KeyPurpose(KeyPurpose::VERIFY),
-                        },
-                        KeyParameter { tag: Tag::DIGEST, value: KPV::Digest(Digest::NONE) },
-                        KeyParameter {
-                            tag: Tag::PADDING,
-                            value: KPV::PaddingMode(PaddingMode::NONE),
-                        },
-                        KeyParameter { tag: Tag::ORIGIN, value: KPV::Origin(KeyOrigin::GENERATED) },
-                        KeyParameter { tag: Tag::OS_VERSION, value: KPV::Integer(110000) },
-                        KeyParameter { tag: Tag::OS_PATCHLEVEL, value: KPV::Integer(202107) },
-                        KeyParameter {
-                            tag: Tag::CREATION_DATETIME,
-                            value: KPV::DateTime(1628871769000),
-                        },
-                        KeyParameter { tag: Tag::VENDOR_PATCHLEVEL, value: KPV::Integer(20210705) },
-                        KeyParameter { tag: Tag::BOOT_PATCHLEVEL, value: KPV::Integer(0) },
-                    ],
-                },
-                // No support for RSA keys in export_key().
-                None,
-            ),
-        ];
-
-        for (input, want, want_format) in tests {
-            let input = hex::decode(input).unwrap();
-            let got = KeyBlob::new_from_serialized(&input, &hidden).expect("invalid keyblob!");
-            assert!(got == want);
-
-            if let Some(want_format) = want_format {
-                let (got_format, _key_material, params) =
-                    export_key(&input, &[]).expect("invalid keyblob!");
-                assert_eq!(got_format, want_format);
-                // All the test cases are software-only keys.
-                assert_eq!(params, got.sw_enforced);
-            }
-        }
-    }
-
-    #[test]
-    fn test_add_der_len() {
-        let tests = [
-            (0, "00"),
-            (1, "01"),
-            (126, "7e"),
-            (127, "7f"),
-            (128, "8180"),
-            (129, "8181"),
-            (255, "81ff"),
-            (256, "820100"),
-            (257, "820101"),
-            (65535, "82ffff"),
-        ];
-        for (input, want) in tests {
-            let mut got = Vec::new();
-            add_der_len(&mut got, input).unwrap();
-            assert_eq!(hex::encode(got), want, " for input length {input}");
-        }
-    }
-
-    #[test]
-    fn test_pkcs8_wrap_key_p256() {
-        // Key material taken from `ec_256_key` in
-        // hardware/interfaces/security/keymint/aidl/vts/function/KeyMintTest.cpp
-        let input = hex::decode(concat!(
-            "3025",   // SEQUENCE (ECPrivateKey)
-            "020101", // INTEGER length 1 value 1 (version)
-            "0420",   // OCTET STRING (privateKey)
-            "737c2ecd7b8d1940bf2930aa9b4ed3ff",
-            "941eed09366bc03299986481f3a4d859",
-        ))
-        .unwrap();
-        let want = hex::decode(concat!(
-            // RFC 5208 s5
-            "3041",             // SEQUENCE (PrivateKeyInfo) {
-            "020100",           // INTEGER length 1 value 0 (version)
-            "3013",             // SEQUENCE length 0x13 (AlgorithmIdentifier) {
-            "0607",             // OBJECT IDENTIFIER length 7 (algorithm)
-            "2a8648ce3d0201",   // 1.2.840.10045.2.1 (ecPublicKey)
-            "0608",             // OBJECT IDENTIFIER length 8 (param)
-            "2a8648ce3d030107", //  1.2.840.10045.3.1.7 (secp256r1)
-            // } end SEQUENCE (AlgorithmIdentifier)
-            "0427",   // OCTET STRING (privateKey) holding...
-            "3025",   // SEQUENCE (ECPrivateKey)
-            "020101", // INTEGER length 1 value 1 (version)
-            "0420",   // OCTET STRING length 0x20 (privateKey)
-            "737c2ecd7b8d1940bf2930aa9b4ed3ff",
-            "941eed09366bc03299986481f3a4d859",
-            // } end SEQUENCE (ECPrivateKey)
-            // } end SEQUENCE (PrivateKeyInfo)
-        ))
-        .unwrap();
-        let got = pkcs8_wrap_nist_key(&input, EcCurve::P_256).unwrap();
-        assert_eq!(hex::encode(got), hex::encode(want), " for input {}", hex::encode(input));
-    }
-
-    #[test]
-    fn test_pkcs8_wrap_key_p521() {
-        // Key material taken from `ec_521_key` in
-        // hardware/interfaces/security/keymint/aidl/vts/function/KeyMintTest.cpp
-        let input = hex::decode(concat!(
-            "3047",   // SEQUENCE length 0xd3 (ECPrivateKey)
-            "020101", // INTEGER length 1 value 1 (version)
-            "0442",   // OCTET STRING length 0x42 (privateKey)
-            "0011458c586db5daa92afab03f4fe46a",
-            "a9d9c3ce9a9b7a006a8384bec4c78e8e",
-            "9d18d7d08b5bcfa0e53c75b064ad51c4",
-            "49bae0258d54b94b1e885ded08ed4fb2",
-            "5ce9",
-            // } end SEQUENCE (ECPrivateKey)
-        ))
-        .unwrap();
-        let want = hex::decode(concat!(
-            // RFC 5208 s5
-            "3060",           // SEQUENCE (PrivateKeyInfo) {
-            "020100",         // INTEGER length 1 value 0 (version)
-            "3010",           // SEQUENCE length 0x10 (AlgorithmIdentifier) {
-            "0607",           // OBJECT IDENTIFIER length 7 (algorithm)
-            "2a8648ce3d0201", // 1.2.840.10045.2.1 (ecPublicKey)
-            "0605",           // OBJECT IDENTIFIER length 5 (param)
-            "2b81040023",     //  1.3.132.0.35 (secp521r1)
-            // } end SEQUENCE (AlgorithmIdentifier)
-            "0449",   // OCTET STRING (privateKey) holding...
-            "3047",   // SEQUENCE (ECPrivateKey)
-            "020101", // INTEGER length 1 value 1 (version)
-            "0442",   // OCTET STRING length 0x42 (privateKey)
-            "0011458c586db5daa92afab03f4fe46a",
-            "a9d9c3ce9a9b7a006a8384bec4c78e8e",
-            "9d18d7d08b5bcfa0e53c75b064ad51c4",
-            "49bae0258d54b94b1e885ded08ed4fb2",
-            "5ce9",
-            // } end SEQUENCE (ECPrivateKey)
-            // } end SEQUENCE (PrivateKeyInfo)
-        ))
-        .unwrap();
-        let got = pkcs8_wrap_nist_key(&input, EcCurve::P_521).unwrap();
-        assert_eq!(hex::encode(got), hex::encode(want), " for input {}", hex::encode(input));
-    }
-}
diff --git a/keystore2/src/sw_keyblob/tests.rs b/keystore2/src/sw_keyblob/tests.rs
new file mode 100644
index 0000000..fe01112
--- /dev/null
+++ b/keystore2/src/sw_keyblob/tests.rs
@@ -0,0 +1,449 @@
+// Copyright 2023, 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.
+
+//! Tests for software-backed keyblobs.
+use super::*;
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+    Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
+    KeyOrigin::KeyOrigin, KeyParameter::KeyParameter, KeyParameterValue::KeyParameterValue as KPV,
+    KeyPurpose::KeyPurpose, PaddingMode::PaddingMode, Tag::Tag,
+};
+
+macro_rules! expect_err {
+    ($result:expr, $err_msg:expr) => {
+        assert!(
+            $result.is_err(),
+            "Expected error containing '{}', got success {:?}",
+            $err_msg,
+            $result
+        );
+        let err = $result.err();
+        assert!(
+            format!("{:?}", err).contains($err_msg),
+            "Unexpected error {:?}, doesn't contain '{}'",
+            err,
+            $err_msg
+        );
+    };
+}
+
+#[test]
+fn test_consume_u8() {
+    let buffer = [1, 2];
+    let mut data = &buffer[..];
+    assert_eq!(1u8, consume_u8(&mut data).unwrap());
+    assert_eq!(2u8, consume_u8(&mut data).unwrap());
+    let result = consume_u8(&mut data);
+    expect_err!(result, "failed to find 1 byte");
+}
+
+#[test]
+fn test_consume_u32() {
+    // All supported platforms are little-endian.
+    let buffer = [
+        0x01, 0x02, 0x03, 0x04, // little-endian u32
+        0x04, 0x03, 0x02, 0x01, // little-endian u32
+        0x11, 0x12, 0x13,
+    ];
+    let mut data = &buffer[..];
+    assert_eq!(0x04030201u32, consume_u32(&mut data).unwrap());
+    assert_eq!(0x01020304u32, consume_u32(&mut data).unwrap());
+    let result = consume_u32(&mut data);
+    expect_err!(result, "failed to find 4 bytes");
+}
+
+#[test]
+fn test_consume_i64() {
+    // All supported platforms are little-endian.
+    let buffer = [
+        0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // little-endian i64
+        0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, // little-endian i64
+        0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+    ];
+    let mut data = &buffer[..];
+    assert_eq!(0x0807060504030201i64, consume_i64(&mut data).unwrap());
+    assert_eq!(0x0102030405060708i64, consume_i64(&mut data).unwrap());
+    let result = consume_i64(&mut data);
+    expect_err!(result, "failed to find 8 bytes");
+}
+
+#[test]
+fn test_consume_vec() {
+    let buffer = [
+        0x01, 0x00, 0x00, 0x00, 0xaa, //
+        0x00, 0x00, 0x00, 0x00, //
+        0x01, 0x00, 0x00, 0x00, 0xbb, //
+        0x07, 0x00, 0x00, 0x00, 0xbb, // not enough data
+    ];
+    let mut data = &buffer[..];
+    assert_eq!(vec![0xaa], consume_vec(&mut data).unwrap());
+    assert_eq!(Vec::<u8>::new(), consume_vec(&mut data).unwrap());
+    assert_eq!(vec![0xbb], consume_vec(&mut data).unwrap());
+    let result = consume_vec(&mut data);
+    expect_err!(result, "failed to find 7 bytes");
+
+    let buffer = [
+        0x01, 0x00, 0x00, //
+    ];
+    let mut data = &buffer[..];
+    let result = consume_vec(&mut data);
+    expect_err!(result, "failed to find 4 bytes");
+}
+
+#[test]
+fn test_key_new_from_serialized() {
+    let hidden = hidden_params(&[], &[SOFTWARE_ROOT_OF_TRUST]);
+    // Test data originally generated by instrumenting Cuttlefish C++ KeyMint while running VTS
+    // tests.
+    let tests = [
+        (
+            concat!(
+                "0010000000d43c2f04f948521b81bdbf001310f5920000000000000000000000",
+                "00000000000c0000006400000002000010200000000300003080000000010000",
+                "2000000000010000200100000004000020020000000600002001000000be0200",
+                "1000000000c1020030b0ad0100c20200307b150300bd020060a8bb52407b0100",
+                "00ce02003011643401cf020030000000003b06b13ae6ae6671",
+            ),
+            KeyBlob {
+                key_material: hex::decode("d43c2f04f948521b81bdbf001310f592").unwrap(),
+                hw_enforced: vec![],
+                sw_enforced: vec![
+                    KeyParameter { tag: Tag::ALGORITHM, value: KPV::Algorithm(Algorithm::AES) },
+                    KeyParameter { tag: Tag::KEY_SIZE, value: KPV::Integer(128) },
+                    KeyParameter { tag: Tag::PURPOSE, value: KPV::KeyPurpose(KeyPurpose::ENCRYPT) },
+                    KeyParameter { tag: Tag::PURPOSE, value: KPV::KeyPurpose(KeyPurpose::DECRYPT) },
+                    KeyParameter { tag: Tag::BLOCK_MODE, value: KPV::BlockMode(BlockMode::CBC) },
+                    KeyParameter { tag: Tag::PADDING, value: KPV::PaddingMode(PaddingMode::NONE) },
+                    KeyParameter { tag: Tag::ORIGIN, value: KPV::Origin(KeyOrigin::GENERATED) },
+                    KeyParameter { tag: Tag::OS_VERSION, value: KPV::Integer(110000) },
+                    KeyParameter { tag: Tag::OS_PATCHLEVEL, value: KPV::Integer(202107) },
+                    KeyParameter {
+                        tag: Tag::CREATION_DATETIME,
+                        value: KPV::DateTime(1628871769000),
+                    },
+                    KeyParameter { tag: Tag::VENDOR_PATCHLEVEL, value: KPV::Integer(20210705) },
+                    KeyParameter { tag: Tag::BOOT_PATCHLEVEL, value: KPV::Integer(0) },
+                ],
+            },
+            Some(KeyFormat::RAW),
+        ),
+        (
+            concat!(
+                "00df0000003081dc020101044200b6ce876b947e263d61b8e3998d50dc0afb6b",
+                "a14e46ab7ca532fbe2a379b155d0a5bb99265402857b1601fb20be6c244bf654",
+                "e9e79413cd503eae3d9cf68ed24f47a00706052b81040023a181890381860004",
+                "006b840f0db0b12f074ab916c7773cfa7d42967c9e5b4fae09cf999f7e116d14",
+                "0743bdd028db0a3fcc670e721b9f00bc7fb70aa401c7d6de6582fc26962a29b7",
+                "45e30142e90685646661550344113aaf28bdee6cb02d19df1faab4398556a909",
+                "7d6f64b95209601a549389a311231c6cce78354f2cdbc3a904abf70686f5f0c3",
+                "b877984d000000000000000000000000000000000c0000006400000002000010",
+                "030000000a000010030000000100002002000000010000200300000005000020",
+                "000000000300003009020000be02001000000000c1020030b0ad0100c2020030",
+                "7b150300bd02006018d352407b010000ce02003011643401cf02003000000000",
+                "2f69002e55e9b0a3"
+            ),
+            KeyBlob {
+                key_material: hex::decode(concat!(
+                    "3081dc020101044200b6ce876b947e263d61b8e3998d50dc0afb6ba14e46ab7c",
+                    "a532fbe2a379b155d0a5bb99265402857b1601fb20be6c244bf654e9e79413cd",
+                    "503eae3d9cf68ed24f47a00706052b81040023a181890381860004006b840f0d",
+                    "b0b12f074ab916c7773cfa7d42967c9e5b4fae09cf999f7e116d140743bdd028",
+                    "db0a3fcc670e721b9f00bc7fb70aa401c7d6de6582fc26962a29b745e30142e9",
+                    "0685646661550344113aaf28bdee6cb02d19df1faab4398556a9097d6f64b952",
+                    "09601a549389a311231c6cce78354f2cdbc3a904abf70686f5f0c3b877984d",
+                ))
+                .unwrap(),
+                hw_enforced: vec![],
+                sw_enforced: vec![
+                    KeyParameter { tag: Tag::ALGORITHM, value: KPV::Algorithm(Algorithm::EC) },
+                    KeyParameter { tag: Tag::EC_CURVE, value: KPV::EcCurve(EcCurve::P_521) },
+                    KeyParameter { tag: Tag::PURPOSE, value: KPV::KeyPurpose(KeyPurpose::SIGN) },
+                    KeyParameter { tag: Tag::PURPOSE, value: KPV::KeyPurpose(KeyPurpose::VERIFY) },
+                    KeyParameter { tag: Tag::DIGEST, value: KPV::Digest(Digest::NONE) },
+                    KeyParameter { tag: Tag::KEY_SIZE, value: KPV::Integer(521) },
+                    KeyParameter { tag: Tag::ORIGIN, value: KPV::Origin(KeyOrigin::GENERATED) },
+                    KeyParameter { tag: Tag::OS_VERSION, value: KPV::Integer(110000) },
+                    KeyParameter { tag: Tag::OS_PATCHLEVEL, value: KPV::Integer(202107) },
+                    KeyParameter {
+                        tag: Tag::CREATION_DATETIME,
+                        value: KPV::DateTime(1628871775000),
+                    },
+                    KeyParameter { tag: Tag::VENDOR_PATCHLEVEL, value: KPV::Integer(20210705) },
+                    KeyParameter { tag: Tag::BOOT_PATCHLEVEL, value: KPV::Integer(0) },
+                ],
+            },
+            Some(KeyFormat::PKCS8),
+        ),
+        (
+            concat!(
+                "0037000000541d4c440223650d5f51753c1abd80c725034485551e874d62327c",
+                "65f6247a057f1218bd6c8cd7d319103ddb823fc11fb6c2c7268b5acc00000000",
+                "0000000000000000000000000c00000064000000020000108000000003000030",
+                "b801000001000020020000000100002003000000050000200400000008000030",
+                "00010000be02001000000000c1020030b0ad0100c20200307b150300bd020060",
+                "00d752407b010000ce02003011643401cf0200300000000036e6986ffc45fbb0",
+            ),
+            KeyBlob {
+                key_material: hex::decode(concat!(
+                    "541d4c440223650d5f51753c1abd80c725034485551e874d62327c65f6247a05",
+                    "7f1218bd6c8cd7d319103ddb823fc11fb6c2c7268b5acc"
+                ))
+                .unwrap(),
+                hw_enforced: vec![],
+                sw_enforced: vec![
+                    KeyParameter { tag: Tag::ALGORITHM, value: KPV::Algorithm(Algorithm::HMAC) },
+                    KeyParameter { tag: Tag::KEY_SIZE, value: KPV::Integer(440) },
+                    KeyParameter { tag: Tag::PURPOSE, value: KPV::KeyPurpose(KeyPurpose::SIGN) },
+                    KeyParameter { tag: Tag::PURPOSE, value: KPV::KeyPurpose(KeyPurpose::VERIFY) },
+                    KeyParameter { tag: Tag::DIGEST, value: KPV::Digest(Digest::SHA_2_256) },
+                    KeyParameter { tag: Tag::MIN_MAC_LENGTH, value: KPV::Integer(256) },
+                    KeyParameter { tag: Tag::ORIGIN, value: KPV::Origin(KeyOrigin::GENERATED) },
+                    KeyParameter { tag: Tag::OS_VERSION, value: KPV::Integer(110000) },
+                    KeyParameter { tag: Tag::OS_PATCHLEVEL, value: KPV::Integer(202107) },
+                    KeyParameter {
+                        tag: Tag::CREATION_DATETIME,
+                        value: KPV::DateTime(1628871776000),
+                    },
+                    KeyParameter { tag: Tag::VENDOR_PATCHLEVEL, value: KPV::Integer(20210705) },
+                    KeyParameter { tag: Tag::BOOT_PATCHLEVEL, value: KPV::Integer(0) },
+                ],
+            },
+            Some(KeyFormat::RAW),
+        ),
+        (
+            concat!(
+                "00a8040000308204a40201000282010100bc47b5c71116766669b91fa747df87",
+                "a1963df83956569d4ac232aeba8a246c0ec73bf606374a6d07f30c2162f97082",
+                "825c7c6e482a2841dfeaec1429d84e52c54a6b2f760dec952c9c44a3c3a80f31",
+                "c1ced84878edd4858059071c4d20d9ab0aae978bd68c1eb448e174a9736c3973",
+                "6838151642eda8215107375865a99a57f29467c74c40f37b0221b93ec3f4f22d",
+                "5337c8bf9245d56936196a92b1dea315ecce8785f9fa9b7d159ca207612cc0de",
+                "b0957d61dbba5d9bd38784f4fecbf233b04e686a340528665ecd03db8e8a09b2",
+                "540c84e45c4a99fb338b76bba7722856b5113341c349708937228f167d238ed8",
+                "efb9cc19547dd620f6a90d95f07e50bfe102030100010282010002f91b69d9af",
+                "59fe87421af9ba60f15c77f9c1c90effd6634332876f8ee5a116b126f55d3703",
+                "8bf9f588ae20c8d951d842e35c9ef35a7822d3ebf72c0b7c3e229b289ae2e178",
+                "a848e06d558c2e03d26871ee98a35f370d461ff1c4acc39d684de680a25ec88e",
+                "e610260e406c400bdeb2893b2d0330cb483e662fa5abd24c2b82143e85dfe30a",
+                "e7a31f8262da2903d882b35a34a26b699ff2d812bad4b126a0065ec0e101d73a",
+                "e6f8b29a9144eb83f54940a371fc7416c2c0370df6a41cb5391f17ba33239e1b",
+                "4217c8db50db5c6bf77ccf621354ecc652a4f7196054c254566fd7b3bc0f3817",
+                "d9380b190bd382aaffa37785759f285194c11a188bccde0e2e2902818100fb23",
+                "3335770c9f3cbd4b6ede5f12d03c449b1997bce06a8249bc3de99972fd0d0a63",
+                "3f7790d1011bf5eedee16fa45a9107a910656ecaee364ce9edb4369843be71f2",
+                "7a74852d6c7215a6cc60d9803bcac544922f806d8e5844e0ddd914bd78009490",
+                "4c2856d2b944fade3fb1d67d4a33fb7663a9ab660ab372c2e4868a0f45990281",
+                "8100bfecf2bb4012e880fd065a0b088f2d757af2878d3f1305f21ce7a7158458",
+                "18e01181ff06b2f406239fc50808ce3dbe7b68ec01174913c0f237feb3c8c7eb",
+                "0078b77fb5b8f214b72f6d3835b1a7ebe8b132feb6cb34ab09ce22b98160fc84",
+                "20fcbf48d1eee49f874e902f049b206a61a095f0405a4935e7c5e49757ab7b57",
+                "298902818100ec0049383e16f3716de5fc5b2677148efe5dceb02483b43399bd",
+                "3765559994a9f3900eed7a7e9e8f3b0eee0e660eca392e3cb736cae612f39e55",
+                "dad696d3821def10d1f8bbca52f5e6d8e7893ffbdcb491aafdc17bebf86f84d2",
+                "d8480ed07a7bf9209d20ef6e79429489d4cb7768281a2f7e32ec1830fd6f6332",
+                "38f521ba764902818100b2c3ce5751580b4e51df3fb175387f5c24b79040a4d6",
+                "603c6265f70018b441ff3aef7d8e4cd2f480ec0906f1c4c0481304e8861f9d46",
+                "93fa48e3a9abc362859eeb343e1c5507ac94b5439ce7ac04154a2fb886a4819b",
+                "2a57e18a2e131b412ac4a09b004766959cdf357745f003e272aab3de02e2d5bc",
+                "2af4ed75760858ab181902818061d19c2a8dcacde104b97f7c4fae11216157c1",
+                "c0a258d882984d12383a73dc56fe2ac93512bb321df9706ecdb2f70a44c949c4",
+                "340a9fae64a0646cf51f37c58c08bebde91667b3b2fa7c895f7983d4786c5526",
+                "1941b3654533b0598383ebbcffcdf28b6cf13d376e3a70b49b14d8d06e8563a2",
+                "47f56a337e3b9845b4f2b61356000000000000000000000000000000000d0000",
+                "007000000002000010010000000300003000080000c800005001000100000000",
+                "0001000020020000000100002003000000050000200000000006000020010000",
+                "00be02001000000000c1020030b0ad0100c20200307b150300bd020060a8bb52",
+                "407b010000ce02003011643401cf02003000000000544862e9c961e857",
+            ),
+            KeyBlob {
+                key_material: hex::decode(concat!(
+                    "308204a40201000282010100bc47b5c71116766669b91fa747df87a1963df839",
+                    "56569d4ac232aeba8a246c0ec73bf606374a6d07f30c2162f97082825c7c6e48",
+                    "2a2841dfeaec1429d84e52c54a6b2f760dec952c9c44a3c3a80f31c1ced84878",
+                    "edd4858059071c4d20d9ab0aae978bd68c1eb448e174a9736c39736838151642",
+                    "eda8215107375865a99a57f29467c74c40f37b0221b93ec3f4f22d5337c8bf92",
+                    "45d56936196a92b1dea315ecce8785f9fa9b7d159ca207612cc0deb0957d61db",
+                    "ba5d9bd38784f4fecbf233b04e686a340528665ecd03db8e8a09b2540c84e45c",
+                    "4a99fb338b76bba7722856b5113341c349708937228f167d238ed8efb9cc1954",
+                    "7dd620f6a90d95f07e50bfe102030100010282010002f91b69d9af59fe87421a",
+                    "f9ba60f15c77f9c1c90effd6634332876f8ee5a116b126f55d37038bf9f588ae",
+                    "20c8d951d842e35c9ef35a7822d3ebf72c0b7c3e229b289ae2e178a848e06d55",
+                    "8c2e03d26871ee98a35f370d461ff1c4acc39d684de680a25ec88ee610260e40",
+                    "6c400bdeb2893b2d0330cb483e662fa5abd24c2b82143e85dfe30ae7a31f8262",
+                    "da2903d882b35a34a26b699ff2d812bad4b126a0065ec0e101d73ae6f8b29a91",
+                    "44eb83f54940a371fc7416c2c0370df6a41cb5391f17ba33239e1b4217c8db50",
+                    "db5c6bf77ccf621354ecc652a4f7196054c254566fd7b3bc0f3817d9380b190b",
+                    "d382aaffa37785759f285194c11a188bccde0e2e2902818100fb233335770c9f",
+                    "3cbd4b6ede5f12d03c449b1997bce06a8249bc3de99972fd0d0a633f7790d101",
+                    "1bf5eedee16fa45a9107a910656ecaee364ce9edb4369843be71f27a74852d6c",
+                    "7215a6cc60d9803bcac544922f806d8e5844e0ddd914bd780094904c2856d2b9",
+                    "44fade3fb1d67d4a33fb7663a9ab660ab372c2e4868a0f459902818100bfecf2",
+                    "bb4012e880fd065a0b088f2d757af2878d3f1305f21ce7a715845818e01181ff",
+                    "06b2f406239fc50808ce3dbe7b68ec01174913c0f237feb3c8c7eb0078b77fb5",
+                    "b8f214b72f6d3835b1a7ebe8b132feb6cb34ab09ce22b98160fc8420fcbf48d1",
+                    "eee49f874e902f049b206a61a095f0405a4935e7c5e49757ab7b572989028181",
+                    "00ec0049383e16f3716de5fc5b2677148efe5dceb02483b43399bd3765559994",
+                    "a9f3900eed7a7e9e8f3b0eee0e660eca392e3cb736cae612f39e55dad696d382",
+                    "1def10d1f8bbca52f5e6d8e7893ffbdcb491aafdc17bebf86f84d2d8480ed07a",
+                    "7bf9209d20ef6e79429489d4cb7768281a2f7e32ec1830fd6f633238f521ba76",
+                    "4902818100b2c3ce5751580b4e51df3fb175387f5c24b79040a4d6603c6265f7",
+                    "0018b441ff3aef7d8e4cd2f480ec0906f1c4c0481304e8861f9d4693fa48e3a9",
+                    "abc362859eeb343e1c5507ac94b5439ce7ac04154a2fb886a4819b2a57e18a2e",
+                    "131b412ac4a09b004766959cdf357745f003e272aab3de02e2d5bc2af4ed7576",
+                    "0858ab181902818061d19c2a8dcacde104b97f7c4fae11216157c1c0a258d882",
+                    "984d12383a73dc56fe2ac93512bb321df9706ecdb2f70a44c949c4340a9fae64",
+                    "a0646cf51f37c58c08bebde91667b3b2fa7c895f7983d4786c55261941b36545",
+                    "33b0598383ebbcffcdf28b6cf13d376e3a70b49b14d8d06e8563a247f56a337e",
+                    "3b9845b4f2b61356",
+                ))
+                .unwrap(),
+                hw_enforced: vec![],
+                sw_enforced: vec![
+                    KeyParameter { tag: Tag::ALGORITHM, value: KPV::Algorithm(Algorithm::RSA) },
+                    KeyParameter { tag: Tag::KEY_SIZE, value: KPV::Integer(2048) },
+                    KeyParameter { tag: Tag::RSA_PUBLIC_EXPONENT, value: KPV::LongInteger(65537) },
+                    KeyParameter { tag: Tag::PURPOSE, value: KPV::KeyPurpose(KeyPurpose::SIGN) },
+                    KeyParameter { tag: Tag::PURPOSE, value: KPV::KeyPurpose(KeyPurpose::VERIFY) },
+                    KeyParameter { tag: Tag::DIGEST, value: KPV::Digest(Digest::NONE) },
+                    KeyParameter { tag: Tag::PADDING, value: KPV::PaddingMode(PaddingMode::NONE) },
+                    KeyParameter { tag: Tag::ORIGIN, value: KPV::Origin(KeyOrigin::GENERATED) },
+                    KeyParameter { tag: Tag::OS_VERSION, value: KPV::Integer(110000) },
+                    KeyParameter { tag: Tag::OS_PATCHLEVEL, value: KPV::Integer(202107) },
+                    KeyParameter {
+                        tag: Tag::CREATION_DATETIME,
+                        value: KPV::DateTime(1628871769000),
+                    },
+                    KeyParameter { tag: Tag::VENDOR_PATCHLEVEL, value: KPV::Integer(20210705) },
+                    KeyParameter { tag: Tag::BOOT_PATCHLEVEL, value: KPV::Integer(0) },
+                ],
+            },
+            // No support for RSA keys in export_key().
+            None,
+        ),
+    ];
+
+    for (input, want, want_format) in tests {
+        let input = hex::decode(input).unwrap();
+        let got = KeyBlob::new_from_serialized(&input, &hidden).expect("invalid keyblob!");
+        assert!(got == want);
+
+        if let Some(want_format) = want_format {
+            let (got_format, _key_material, params) =
+                export_key(&input, &[]).expect("invalid keyblob!");
+            assert_eq!(got_format, want_format);
+            // All the test cases are software-only keys.
+            assert_eq!(params, got.sw_enforced);
+        }
+    }
+}
+
+#[test]
+fn test_add_der_len() {
+    let tests = [
+        (0, "00"),
+        (1, "01"),
+        (126, "7e"),
+        (127, "7f"),
+        (128, "8180"),
+        (129, "8181"),
+        (255, "81ff"),
+        (256, "820100"),
+        (257, "820101"),
+        (65535, "82ffff"),
+    ];
+    for (input, want) in tests {
+        let mut got = Vec::new();
+        add_der_len(&mut got, input).unwrap();
+        assert_eq!(hex::encode(got), want, " for input length {input}");
+    }
+}
+
+#[test]
+fn test_pkcs8_wrap_key_p256() {
+    // Key material taken from `ec_256_key` in
+    // hardware/interfaces/security/keymint/aidl/vts/function/KeyMintTest.cpp
+    let input = hex::decode(concat!(
+        "3025",   // SEQUENCE (ECPrivateKey)
+        "020101", // INTEGER length 1 value 1 (version)
+        "0420",   // OCTET STRING (privateKey)
+        "737c2ecd7b8d1940bf2930aa9b4ed3ff",
+        "941eed09366bc03299986481f3a4d859",
+    ))
+    .unwrap();
+    let want = hex::decode(concat!(
+        // RFC 5208 s5
+        "3041",             // SEQUENCE (PrivateKeyInfo) {
+        "020100",           // INTEGER length 1 value 0 (version)
+        "3013",             // SEQUENCE length 0x13 (AlgorithmIdentifier) {
+        "0607",             // OBJECT IDENTIFIER length 7 (algorithm)
+        "2a8648ce3d0201",   // 1.2.840.10045.2.1 (ecPublicKey)
+        "0608",             // OBJECT IDENTIFIER length 8 (param)
+        "2a8648ce3d030107", //  1.2.840.10045.3.1.7 (secp256r1)
+        // } end SEQUENCE (AlgorithmIdentifier)
+        "0427",   // OCTET STRING (privateKey) holding...
+        "3025",   // SEQUENCE (ECPrivateKey)
+        "020101", // INTEGER length 1 value 1 (version)
+        "0420",   // OCTET STRING length 0x20 (privateKey)
+        "737c2ecd7b8d1940bf2930aa9b4ed3ff",
+        "941eed09366bc03299986481f3a4d859",
+        // } end SEQUENCE (ECPrivateKey)
+        // } end SEQUENCE (PrivateKeyInfo)
+    ))
+    .unwrap();
+    let got = pkcs8_wrap_nist_key(&input, EcCurve::P_256).unwrap();
+    assert_eq!(hex::encode(got), hex::encode(want), " for input {}", hex::encode(input));
+}
+
+#[test]
+fn test_pkcs8_wrap_key_p521() {
+    // Key material taken from `ec_521_key` in
+    // hardware/interfaces/security/keymint/aidl/vts/function/KeyMintTest.cpp
+    let input = hex::decode(concat!(
+        "3047",   // SEQUENCE length 0xd3 (ECPrivateKey)
+        "020101", // INTEGER length 1 value 1 (version)
+        "0442",   // OCTET STRING length 0x42 (privateKey)
+        "0011458c586db5daa92afab03f4fe46a",
+        "a9d9c3ce9a9b7a006a8384bec4c78e8e",
+        "9d18d7d08b5bcfa0e53c75b064ad51c4",
+        "49bae0258d54b94b1e885ded08ed4fb2",
+        "5ce9",
+        // } end SEQUENCE (ECPrivateKey)
+    ))
+    .unwrap();
+    let want = hex::decode(concat!(
+        // RFC 5208 s5
+        "3060",           // SEQUENCE (PrivateKeyInfo) {
+        "020100",         // INTEGER length 1 value 0 (version)
+        "3010",           // SEQUENCE length 0x10 (AlgorithmIdentifier) {
+        "0607",           // OBJECT IDENTIFIER length 7 (algorithm)
+        "2a8648ce3d0201", // 1.2.840.10045.2.1 (ecPublicKey)
+        "0605",           // OBJECT IDENTIFIER length 5 (param)
+        "2b81040023",     //  1.3.132.0.35 (secp521r1)
+        // } end SEQUENCE (AlgorithmIdentifier)
+        "0449",   // OCTET STRING (privateKey) holding...
+        "3047",   // SEQUENCE (ECPrivateKey)
+        "020101", // INTEGER length 1 value 1 (version)
+        "0442",   // OCTET STRING length 0x42 (privateKey)
+        "0011458c586db5daa92afab03f4fe46a",
+        "a9d9c3ce9a9b7a006a8384bec4c78e8e",
+        "9d18d7d08b5bcfa0e53c75b064ad51c4",
+        "49bae0258d54b94b1e885ded08ed4fb2",
+        "5ce9",
+        // } end SEQUENCE (ECPrivateKey)
+        // } end SEQUENCE (PrivateKeyInfo)
+    ))
+    .unwrap();
+    let got = pkcs8_wrap_nist_key(&input, EcCurve::P_521).unwrap();
+    assert_eq!(hex::encode(got), hex::encode(want), " for input {}", hex::encode(input));
+}
diff --git a/keystore2/src/utils.rs b/keystore2/src/utils.rs
index 54f382d..22c0522 100644
--- a/keystore2/src/utils.rs
+++ b/keystore2/src/utils.rs
@@ -49,6 +49,9 @@
 use keystore2_crypto::{aes_gcm_decrypt, aes_gcm_encrypt, ZVec};
 use std::iter::IntoIterator;
 
+#[cfg(test)]
+mod tests;
+
 /// Per RFC 5280 4.1.2.5, an undefined expiration (not-after) field should be set to GeneralizedTime
 /// 999912312359559, which is 253402300799000 ms from Jan 1, 1970.
 pub const UNDEFINED_NOT_AFTER: i64 = 253402300799000i64;
@@ -628,130 +631,3 @@
         aes_gcm_encrypt(plaintext, self.key()).context(ks_err!("Encryption failed."))
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use anyhow::Result;
-
-    #[test]
-    fn check_device_attestation_permissions_test() -> Result<()> {
-        check_device_attestation_permissions().or_else(|error| {
-            match error.root_cause().downcast_ref::<Error>() {
-                // Expected: the context for this test might not be allowed to attest device IDs.
-                Some(Error::Km(ErrorCode::CANNOT_ATTEST_IDS)) => Ok(()),
-                // Other errors are unexpected
-                _ => Err(error),
-            }
-        })
-    }
-
-    fn create_key_descriptors_from_aliases(key_aliases: &[&str]) -> Vec<KeyDescriptor> {
-        key_aliases
-            .iter()
-            .map(|key_alias| KeyDescriptor {
-                domain: Domain::APP,
-                nspace: 0,
-                alias: Some(key_alias.to_string()),
-                blob: None,
-            })
-            .collect::<Vec<KeyDescriptor>>()
-    }
-
-    fn aliases_from_key_descriptors(key_descriptors: &[KeyDescriptor]) -> Vec<String> {
-        key_descriptors
-            .iter()
-            .map(
-                |kd| {
-                    if let Some(alias) = &kd.alias {
-                        String::from(alias)
-                    } else {
-                        String::from("")
-                    }
-                },
-            )
-            .collect::<Vec<String>>()
-    }
-
-    #[test]
-    fn test_safe_amount_to_return() -> Result<()> {
-        let key_aliases = vec!["key1", "key2", "key3"];
-        let key_descriptors = create_key_descriptors_from_aliases(&key_aliases);
-
-        assert_eq!(estimate_safe_amount_to_return(Domain::APP, 1017, &key_descriptors, 20), 1);
-        assert_eq!(estimate_safe_amount_to_return(Domain::APP, 1017, &key_descriptors, 50), 2);
-        assert_eq!(estimate_safe_amount_to_return(Domain::APP, 1017, &key_descriptors, 100), 3);
-        Ok(())
-    }
-
-    #[test]
-    fn test_merge_and_sort_lists_without_filtering() -> Result<()> {
-        let legacy_key_aliases = vec!["key_c", "key_a", "key_b"];
-        let legacy_key_descriptors = create_key_descriptors_from_aliases(&legacy_key_aliases);
-        let db_key_aliases = vec!["key_a", "key_d"];
-        let db_key_descriptors = create_key_descriptors_from_aliases(&db_key_aliases);
-        let result =
-            merge_and_filter_key_entry_lists(&legacy_key_descriptors, &db_key_descriptors, None);
-        assert_eq!(aliases_from_key_descriptors(&result), vec!["key_a", "key_b", "key_c", "key_d"]);
-        Ok(())
-    }
-
-    #[test]
-    fn test_merge_and_sort_lists_with_filtering() -> Result<()> {
-        let legacy_key_aliases = vec!["key_f", "key_a", "key_e", "key_b"];
-        let legacy_key_descriptors = create_key_descriptors_from_aliases(&legacy_key_aliases);
-        let db_key_aliases = vec!["key_c", "key_g"];
-        let db_key_descriptors = create_key_descriptors_from_aliases(&db_key_aliases);
-        let result = merge_and_filter_key_entry_lists(
-            &legacy_key_descriptors,
-            &db_key_descriptors,
-            Some("key_b"),
-        );
-        assert_eq!(aliases_from_key_descriptors(&result), vec!["key_c", "key_e", "key_f", "key_g"]);
-        Ok(())
-    }
-
-    #[test]
-    fn test_merge_and_sort_lists_with_filtering_and_dups() -> Result<()> {
-        let legacy_key_aliases = vec!["key_f", "key_a", "key_e", "key_b"];
-        let legacy_key_descriptors = create_key_descriptors_from_aliases(&legacy_key_aliases);
-        let db_key_aliases = vec!["key_d", "key_e", "key_g"];
-        let db_key_descriptors = create_key_descriptors_from_aliases(&db_key_aliases);
-        let result = merge_and_filter_key_entry_lists(
-            &legacy_key_descriptors,
-            &db_key_descriptors,
-            Some("key_c"),
-        );
-        assert_eq!(aliases_from_key_descriptors(&result), vec!["key_d", "key_e", "key_f", "key_g"]);
-        Ok(())
-    }
-
-    #[test]
-    fn test_list_key_parameters_with_filter_on_security_sensitive_info() -> Result<()> {
-        let params = vec![
-            KmKeyParameter { tag: Tag::APPLICATION_ID, value: KeyParameterValue::Integer(0) },
-            KmKeyParameter { tag: Tag::APPLICATION_DATA, value: KeyParameterValue::Integer(0) },
-            KmKeyParameter {
-                tag: Tag::CERTIFICATE_NOT_AFTER,
-                value: KeyParameterValue::DateTime(UNDEFINED_NOT_AFTER),
-            },
-            KmKeyParameter {
-                tag: Tag::CERTIFICATE_NOT_BEFORE,
-                value: KeyParameterValue::DateTime(0),
-            },
-        ];
-        let wanted = vec![
-            KmKeyParameter {
-                tag: Tag::CERTIFICATE_NOT_AFTER,
-                value: KeyParameterValue::DateTime(UNDEFINED_NOT_AFTER),
-            },
-            KmKeyParameter {
-                tag: Tag::CERTIFICATE_NOT_BEFORE,
-                value: KeyParameterValue::DateTime(0),
-            },
-        ];
-
-        assert_eq!(log_security_safe_params(&params), wanted);
-        Ok(())
-    }
-}
diff --git a/keystore2/src/utils/tests.rs b/keystore2/src/utils/tests.rs
new file mode 100644
index 0000000..618ea47
--- /dev/null
+++ b/keystore2/src/utils/tests.rs
@@ -0,0 +1,125 @@
+// 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.
+
+//! Utility functions tests.
+
+use super::*;
+use anyhow::Result;
+
+#[test]
+fn check_device_attestation_permissions_test() -> Result<()> {
+    check_device_attestation_permissions().or_else(|error| {
+        match error.root_cause().downcast_ref::<Error>() {
+            // Expected: the context for this test might not be allowed to attest device IDs.
+            Some(Error::Km(ErrorCode::CANNOT_ATTEST_IDS)) => Ok(()),
+            // Other errors are unexpected
+            _ => Err(error),
+        }
+    })
+}
+
+fn create_key_descriptors_from_aliases(key_aliases: &[&str]) -> Vec<KeyDescriptor> {
+    key_aliases
+        .iter()
+        .map(|key_alias| KeyDescriptor {
+            domain: Domain::APP,
+            nspace: 0,
+            alias: Some(key_alias.to_string()),
+            blob: None,
+        })
+        .collect::<Vec<KeyDescriptor>>()
+}
+
+fn aliases_from_key_descriptors(key_descriptors: &[KeyDescriptor]) -> Vec<String> {
+    key_descriptors
+        .iter()
+        .map(|kd| if let Some(alias) = &kd.alias { String::from(alias) } else { String::from("") })
+        .collect::<Vec<String>>()
+}
+
+#[test]
+fn test_safe_amount_to_return() -> Result<()> {
+    let key_aliases = vec!["key1", "key2", "key3"];
+    let key_descriptors = create_key_descriptors_from_aliases(&key_aliases);
+
+    assert_eq!(estimate_safe_amount_to_return(Domain::APP, 1017, &key_descriptors, 20), 1);
+    assert_eq!(estimate_safe_amount_to_return(Domain::APP, 1017, &key_descriptors, 50), 2);
+    assert_eq!(estimate_safe_amount_to_return(Domain::APP, 1017, &key_descriptors, 100), 3);
+    Ok(())
+}
+
+#[test]
+fn test_merge_and_sort_lists_without_filtering() -> Result<()> {
+    let legacy_key_aliases = vec!["key_c", "key_a", "key_b"];
+    let legacy_key_descriptors = create_key_descriptors_from_aliases(&legacy_key_aliases);
+    let db_key_aliases = vec!["key_a", "key_d"];
+    let db_key_descriptors = create_key_descriptors_from_aliases(&db_key_aliases);
+    let result =
+        merge_and_filter_key_entry_lists(&legacy_key_descriptors, &db_key_descriptors, None);
+    assert_eq!(aliases_from_key_descriptors(&result), vec!["key_a", "key_b", "key_c", "key_d"]);
+    Ok(())
+}
+
+#[test]
+fn test_merge_and_sort_lists_with_filtering() -> Result<()> {
+    let legacy_key_aliases = vec!["key_f", "key_a", "key_e", "key_b"];
+    let legacy_key_descriptors = create_key_descriptors_from_aliases(&legacy_key_aliases);
+    let db_key_aliases = vec!["key_c", "key_g"];
+    let db_key_descriptors = create_key_descriptors_from_aliases(&db_key_aliases);
+    let result = merge_and_filter_key_entry_lists(
+        &legacy_key_descriptors,
+        &db_key_descriptors,
+        Some("key_b"),
+    );
+    assert_eq!(aliases_from_key_descriptors(&result), vec!["key_c", "key_e", "key_f", "key_g"]);
+    Ok(())
+}
+
+#[test]
+fn test_merge_and_sort_lists_with_filtering_and_dups() -> Result<()> {
+    let legacy_key_aliases = vec!["key_f", "key_a", "key_e", "key_b"];
+    let legacy_key_descriptors = create_key_descriptors_from_aliases(&legacy_key_aliases);
+    let db_key_aliases = vec!["key_d", "key_e", "key_g"];
+    let db_key_descriptors = create_key_descriptors_from_aliases(&db_key_aliases);
+    let result = merge_and_filter_key_entry_lists(
+        &legacy_key_descriptors,
+        &db_key_descriptors,
+        Some("key_c"),
+    );
+    assert_eq!(aliases_from_key_descriptors(&result), vec!["key_d", "key_e", "key_f", "key_g"]);
+    Ok(())
+}
+
+#[test]
+fn test_list_key_parameters_with_filter_on_security_sensitive_info() -> Result<()> {
+    let params = vec![
+        KmKeyParameter { tag: Tag::APPLICATION_ID, value: KeyParameterValue::Integer(0) },
+        KmKeyParameter { tag: Tag::APPLICATION_DATA, value: KeyParameterValue::Integer(0) },
+        KmKeyParameter {
+            tag: Tag::CERTIFICATE_NOT_AFTER,
+            value: KeyParameterValue::DateTime(UNDEFINED_NOT_AFTER),
+        },
+        KmKeyParameter { tag: Tag::CERTIFICATE_NOT_BEFORE, value: KeyParameterValue::DateTime(0) },
+    ];
+    let wanted = vec![
+        KmKeyParameter {
+            tag: Tag::CERTIFICATE_NOT_AFTER,
+            value: KeyParameterValue::DateTime(UNDEFINED_NOT_AFTER),
+        },
+        KmKeyParameter { tag: Tag::CERTIFICATE_NOT_BEFORE, value: KeyParameterValue::DateTime(0) },
+    ];
+
+    assert_eq!(log_security_safe_params(&params), wanted);
+    Ok(())
+}