Merge "Add IKeystoreAuthorization AIDL interface with addAuthToken method."
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index e63a469..7bd3c77 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -49,6 +49,7 @@
         "liblazy_static",
         "liblibsqlite3_sys",
         "liblog_rust",
+        "librand",
         "librusqlite",
         "libthiserror",
     ],
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index 45d561a..9086faf 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -41,6 +41,7 @@
 //! from the database module these functions take permission check
 //! callbacks.
 
+use crate::db_utils;
 use crate::error::{Error as KsError, ResponseCode};
 use crate::key_parameter::{KeyParameter, SqlField, Tag};
 use crate::permission::KeyPermSet;
@@ -56,11 +57,12 @@
 use rand::prelude::random;
 use rusqlite::{
     params, types::FromSql, types::FromSqlResult, types::ToSqlOutput, types::ValueRef, Connection,
-    OptionalExtension, Row, Rows, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
+    OptionalExtension, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
 };
 use std::{
     collections::HashSet,
-    sync::{Condvar, Mutex, Once},
+    path::Path,
+    sync::{Condvar, Mutex},
 };
 #[cfg(test)]
 use tests::random;
@@ -236,8 +238,6 @@
     }
 }
 
-static INIT_TABLES: Once = Once::new();
-
 /// KeystoreDB wraps a connection to an SQLite database and tracks its
 /// ownership. It also implements all of Keystore 2.0's database functionality.
 pub struct KeystoreDB {
@@ -246,15 +246,26 @@
 
 impl KeystoreDB {
     /// This will create a new database connection connecting the two
-    /// files persistent.sqlite and perboot.sqlite in the current working
-    /// directory, which is usually `/data/misc/keystore/`.
-    /// It also attempts to initialize all of the tables on the first instantiation
-    /// per service startup. KeystoreDB cannot be used by multiple threads.
+    /// files persistent.sqlite and perboot.sqlite in the given directory.
+    /// It also attempts to initialize all of the tables.
+    /// KeystoreDB cannot be used by multiple threads.
     /// Each thread should open their own connection using `thread_local!`.
-    pub fn new() -> Result<Self> {
-        let conn = Self::make_connection("file:persistent.sqlite", "file:perboot.sqlite")?;
+    pub fn new(db_root: &Path) -> Result<Self> {
+        // Build the path to the sqlite files.
+        let mut persistent_path = db_root.to_path_buf();
+        persistent_path.push("persistent.sqlite");
+        let mut perboot_path = db_root.to_path_buf();
+        perboot_path.push("perboot.sqlite");
 
-        INIT_TABLES.call_once(|| Self::init_tables(&conn).expect("Failed to initialize tables."));
+        // Now convert them to strings prefixed with "file:"
+        let mut persistent_path_str = "file:".to_owned();
+        persistent_path_str.push_str(&persistent_path.to_string_lossy());
+        let mut perboot_path_str = "file:".to_owned();
+        perboot_path_str.push_str(&perboot_path.to_string_lossy());
+
+        let conn = Self::make_connection(&persistent_path_str, &perboot_path_str)?;
+
+        Self::init_tables(&conn)?;
         Ok(Self { conn })
     }
 
@@ -298,14 +309,8 @@
         )
         .context("Failed to initialize \"keyparameter\" table.")?;
 
-        // TODO only drop the perboot table if we start up for the first time per boot.
-        // Right now this is done once per startup which will lose some information
-        // upon a crash.
-        // Note: This is no regression with respect to the legacy Keystore.
-        conn.execute("DROP TABLE IF EXISTS perboot.grant;", NO_PARAMS)
-            .context("Failed to drop perboot.grant table")?;
         conn.execute(
-            "CREATE TABLE perboot.grant (
+            "CREATE TABLE IF NOT EXISTS persistent.grant (
                     id INTEGER UNIQUE,
                     grantee INTEGER,
                     keyentryid INTEGER,
@@ -385,24 +390,30 @@
         key_id: &KeyIdGuard,
         params: impl IntoIterator<Item = &'a KeyParameter>,
     ) -> Result<()> {
-        let mut stmt = self
+        let tx = self
             .conn
-            .prepare(
-                "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
+            .transaction_with_behavior(TransactionBehavior::Immediate)
+            .context("In insert_keyparameter: Failed to start transaction.")?;
+        {
+            let mut stmt = tx
+                .prepare(
+                    "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
                     VALUES (?, ?, ?, ?);",
-            )
-            .context("In insert_keyparameter: Failed to prepare statement.")?;
+                )
+                .context("In insert_keyparameter: Failed to prepare statement.")?;
 
-        let iter = params.into_iter();
-        for p in iter {
-            stmt.insert(params![
-                key_id.0,
-                p.get_tag().0,
-                p.key_parameter_value(),
-                p.security_level().0
-            ])
-            .with_context(|| format!("In insert_keyparameter: Failed to insert {:?}", p))?;
+            let iter = params.into_iter();
+            for p in iter {
+                stmt.insert(params![
+                    key_id.0,
+                    p.get_tag().0,
+                    p.key_parameter_value(),
+                    p.security_level().0
+                ])
+                .with_context(|| format!("In insert_keyparameter: Failed to insert {:?}", p))?;
+            }
         }
+        tx.commit().context("In insert_keyparameter: Failed to commit transaction.")?;
         Ok(())
     }
 
@@ -478,7 +489,7 @@
         let mut rows = stmt
             .query(params![key.domain.0 as u32, key.nspace, alias])
             .context("In load_key_entry_id: Failed to read from keyentry table.")?;
-        Self::with_rows_extract_one(&mut rows, |row| {
+        db_utils::with_rows_extract_one(&mut rows, |row| {
             row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
                 .get(0)
                 .context("Failed to unpack id.")
@@ -527,7 +538,7 @@
             Domain::GRANT => {
                 let mut stmt = tx
                     .prepare(
-                        "SELECT keyentryid, access_vector FROM perboot.grant
+                        "SELECT keyentryid, access_vector FROM persistent.grant
                             WHERE grantee = ? AND id = ?;",
                     )
                     .context("Domain::GRANT prepare statement failed")?;
@@ -535,7 +546,7 @@
                     .query(params![caller_uid as i64, key.nspace])
                     .context("Domain:Grant: query failed.")?;
                 let (key_id, access_vector): (i64, i32) =
-                    Self::with_rows_extract_one(&mut rows, |row| {
+                    db_utils::with_rows_extract_one(&mut rows, |row| {
                         let r =
                             row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
                         Ok((
@@ -560,7 +571,7 @@
                 let mut rows =
                     stmt.query(params![key.nspace]).context("Domain::KEY_ID: query failed.")?;
                 let (domain, namespace): (Domain, i64) =
-                    Self::with_rows_extract_one(&mut rows, |row| {
+                    db_utils::with_rows_extract_one(&mut rows, |row| {
                         let r =
                             row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
                         Ok((
@@ -599,7 +610,7 @@
         let mut km_blob: Option<Vec<u8>> = None;
         let mut cert_blob: Option<Vec<u8>> = None;
         let mut cert_chain_blob: Option<Vec<u8>> = None;
-        Self::with_rows_extract_all(&mut rows, |row| {
+        db_utils::with_rows_extract_all(&mut rows, |row| {
             let sub_type: SubComponentType =
                 row.get(2).context("Failed to extract subcomponent_type.")?;
             match (sub_type, load_bits.load_public()) {
@@ -640,7 +651,7 @@
 
         let mut rows =
             stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
-        Self::with_rows_extract_all(&mut rows, |row| {
+        db_utils::with_rows_extract_all(&mut rows, |row| {
             let tag = Tag(row.get(0).context("Failed to read tag.")?);
             let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
             parameters.push(
@@ -754,6 +765,35 @@
         ))
     }
 
+    /// Returns a list of KeyDescriptors in the selected domain/namespace.
+    /// The key descriptors will have the domain, nspace, and alias field set.
+    /// Domain must be APP or SELINUX, the caller must make sure of that.
+    pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
+        let mut stmt = self
+            .conn
+            .prepare(
+                "SELECT alias FROM persistent.keyentry
+             WHERE domain = ? AND namespace = ? AND alias IS NOT NULL;",
+            )
+            .context("In list: Failed to prepare.")?;
+
+        let mut rows =
+            stmt.query(params![domain.0 as u32, namespace]).context("In list: Failed to query.")?;
+
+        let mut descriptors: Vec<KeyDescriptor> = Vec::new();
+        db_utils::with_rows_extract_all(&mut rows, |row| {
+            descriptors.push(KeyDescriptor {
+                domain,
+                nspace: namespace,
+                alias: Some(row.get(0).context("Trying to extract alias.")?),
+                blob: None,
+            });
+            Ok(())
+        })
+        .context("In list.")?;
+        Ok(descriptors)
+    }
+
     /// Adds a grant to the grant table.
     /// Like `load_key_entry` this function loads the access tuple before
     /// it uses the callback for a permission check. Upon success,
@@ -795,7 +835,7 @@
 
         let grant_id = if let Some(grant_id) = tx
             .query_row(
-                "SELECT id FROM perboot.grant
+                "SELECT id FROM persistent.grant
                 WHERE keyentryid = ? AND grantee = ?;",
                 params![key_id, grantee_uid],
                 |row| row.get(0),
@@ -804,7 +844,7 @@
             .context("In grant: Failed get optional existing grant id.")?
         {
             tx.execute(
-                "UPDATE perboot.grant
+                "UPDATE persistent.grant
                     SET access_vector = ?
                     WHERE id = ?;",
                 params![i32::from(access_vector), grant_id],
@@ -814,7 +854,7 @@
         } else {
             Self::insert_with_retry(|id| {
                 tx.execute(
-                    "INSERT INTO perboot.grant (id, grantee, keyentryid, access_vector)
+                    "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
                         VALUES (?, ?, ?, ?);",
                     params![id, grantee_uid, key_id, i32::from(access_vector)],
                 )
@@ -850,7 +890,7 @@
         check_permission(&access_key_descriptor).context("In grant: check_permission failed.")?;
 
         tx.execute(
-            "DELETE FROM perboot.grant
+            "DELETE FROM persistent.grant
                 WHERE keyentryid = ? AND grantee = ?;",
             params![key_id, grantee_uid],
         )
@@ -883,41 +923,6 @@
             }
         }
     }
-
-    // Takes Rows as returned by a query call on prepared statement.
-    // Extracts exactly one row with the `row_extractor` and fails if more
-    // rows are available.
-    // If no row was found, `None` is passed to the `row_extractor`.
-    // This allows the row extractor to decide on an error condition or
-    // a different default behavior.
-    fn with_rows_extract_one<'a, T, F>(rows: &mut Rows<'a>, row_extractor: F) -> Result<T>
-    where
-        F: FnOnce(Option<&Row<'a>>) -> Result<T>,
-    {
-        let result =
-            row_extractor(rows.next().context("with_rows_extract_one: Failed to unpack row.")?);
-
-        rows.next()
-            .context("In with_rows_extract_one: Failed to unpack unexpected row.")?
-            .map_or_else(|| Ok(()), |_| Err(KsError::sys()))
-            .context("In with_rows_extract_one: Unexpected row.")?;
-
-        result
-    }
-
-    fn with_rows_extract_all<'a, F>(rows: &mut Rows<'a>, mut row_extractor: F) -> Result<()>
-    where
-        F: FnMut(&Row<'a>) -> Result<()>,
-    {
-        loop {
-            match rows.next().context("In with_rows_extract_all: Failed to unpack row")? {
-                Some(row) => {
-                    row_extractor(&row).context("In with_rows_extract_all.")?;
-                }
-                None => break Ok(()),
-            }
-        }
-    }
 }
 
 #[cfg(test)]
@@ -930,15 +935,13 @@
     };
     use crate::key_perm_set;
     use crate::permission::{KeyPerm, KeyPermSet};
+    use crate::test::utils::TempDir;
     use rusqlite::NO_PARAMS;
     use std::cell::RefCell;
     use std::sync::atomic::{AtomicU8, Ordering};
     use std::sync::Arc;
     use std::thread;
 
-    static PERSISTENT_TEST_SQL: &str = "/data/local/tmp/persistent.sqlite";
-    static PERBOOT_TEST_SQL: &str = "/data/local/tmp/perboot.sqlite";
-
     fn new_test_db() -> Result<KeystoreDB> {
         let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
 
@@ -946,13 +949,6 @@
         Ok(KeystoreDB { conn })
     }
 
-    fn new_test_db_with_persistent_file() -> Result<KeystoreDB> {
-        let conn = KeystoreDB::make_connection(PERSISTENT_TEST_SQL, PERBOOT_TEST_SQL)?;
-
-        KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
-        Ok(KeystoreDB { conn })
-    }
-
     // Ensure that we're using the "injected" random function, not the real one.
     #[test]
     fn test_mocked_random() {
@@ -976,44 +972,30 @@
             .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(), 3);
+        assert_eq!(tables.len(), 4);
         assert_eq!(tables[0], "blobentry");
-        assert_eq!(tables[1], "keyentry");
-        assert_eq!(tables[2], "keyparameter");
+        assert_eq!(tables[1], "grant");
+        assert_eq!(tables[2], "keyentry");
+        assert_eq!(tables[3], "keyparameter");
         let tables = db
             .conn
             .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
             .query_map(params![], |row| row.get(0))?
             .collect::<rusqlite::Result<Vec<String>>>()?;
-        assert_eq!(tables.len(), 1);
-        assert_eq!(tables[0], "grant");
-        Ok(())
-    }
-
-    #[test]
-    fn test_no_persistence_for_tests() -> Result<()> {
-        let db = new_test_db()?;
-
-        db.create_key_entry(Domain::APP, 100)?;
-        let entries = get_keyentry(&db)?;
-        assert_eq!(entries.len(), 1);
-        let db = new_test_db()?;
-
-        let entries = get_keyentry(&db)?;
-        assert_eq!(entries.len(), 0);
+        assert_eq!(tables.len(), 0);
         Ok(())
     }
 
     #[test]
     fn test_persistence_for_files() -> Result<()> {
-        let _file_guard_persistent = TempFile { filename: PERSISTENT_TEST_SQL };
-        let _file_guard_perboot = TempFile { filename: PERBOOT_TEST_SQL };
-        let db = new_test_db_with_persistent_file()?;
+        let temp_dir = TempDir::new("persistent_db_test")?;
+        let db = KeystoreDB::new(temp_dir.path())?;
 
         db.create_key_entry(Domain::APP, 100)?;
         let entries = get_keyentry(&db)?;
         assert_eq!(entries.len(), 1);
-        let db = new_test_db_with_persistent_file()?;
+
+        let db = KeystoreDB::new(temp_dir.path())?;
 
         let entries_new = get_keyentry(&db)?;
         assert_eq!(entries, entries_new);
@@ -1230,7 +1212,7 @@
             // Limiting scope of stmt, because it borrows db.
             let mut stmt = db
                 .conn
-                .prepare("SELECT id, grantee, keyentryid, access_vector FROM perboot.grant;")?;
+                .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
             let mut rows =
                 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
                     Ok((
@@ -1438,22 +1420,12 @@
 
     static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
 
-    static KEY_LOCK_TEST_SQL: &str = "/data/local/tmp/persistent_key_lock.sqlite";
-    static KEY_LOCK_PERBOOT_TEST_SQL: &str = "/data/local/tmp/perboot_key_lock.sqlite";
-
-    fn new_test_db_with_persistent_file_key_lock() -> Result<KeystoreDB> {
-        let conn = KeystoreDB::make_connection(KEY_LOCK_TEST_SQL, KEY_LOCK_PERBOOT_TEST_SQL)?;
-
-        KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
-        Ok(KeystoreDB { conn })
-    }
-
     #[test]
     fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
         let handle = {
-            let _file_guard_persistent = Arc::new(TempFile { filename: KEY_LOCK_TEST_SQL });
-            let _file_guard_perboot = Arc::new(TempFile { filename: KEY_LOCK_PERBOOT_TEST_SQL });
-            let mut db = new_test_db_with_persistent_file_key_lock()?;
+            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())?;
             let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS)
                 .context("test_insert_and_load_full_keyentry_domain_app")?
                 .0;
@@ -1490,9 +1462,8 @@
             // of `state` from 1 to 2, despite having a whole second to overtake
             // the primary thread.
             let handle = thread::spawn(move || {
-                let _file_a = _file_guard_persistent;
-                let _file_b = _file_guard_perboot;
-                let mut db = new_test_db_with_persistent_file_key_lock().unwrap();
+                let temp_dir = temp_dir_clone;
+                let mut db = KeystoreDB::new(temp_dir.path()).unwrap();
                 assert!(db
                     .load_key_entry(
                         KeyDescriptor {
@@ -1529,6 +1500,90 @@
         Ok(())
     }
 
+    #[test]
+    fn list() -> Result<()> {
+        let temp_dir = TempDir::new("list_test")?;
+        let mut db = KeystoreDB::new(temp_dir.path())?;
+        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).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(*domain, *namespace)?;
+            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, 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(Domain::SELINUX, 101)?);
+
+        Ok(())
+    }
+
     // Helpers
 
     // Checks that the given result is an error containing the given string.
@@ -1846,8 +1901,9 @@
     }
 
     fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
-        let mut stmt =
-            db.conn.prepare("SELECT id, grantee, keyentryid, access_vector FROM perboot.grant;")?;
+        let mut stmt = db
+            .conn
+            .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
         let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
             Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
         })?;
@@ -1860,18 +1916,6 @@
         Ok(())
     }
 
-    // A class that deletes a file when it is dropped.
-    // TODO: If we ever add a crate that does this, we can use it instead.
-    struct TempFile {
-        filename: &'static str,
-    }
-
-    impl Drop for TempFile {
-        fn drop(&mut self) {
-            std::fs::remove_file(self.filename).expect("Cannot delete temporary file");
-        }
-    }
-
     // Use a custom random number generator that repeats each number once.
     // This allows us to test repeated elements.
 
diff --git a/keystore2/src/db_utils.rs b/keystore2/src/db_utils.rs
new file mode 100644
index 0000000..615005f
--- /dev/null
+++ b/keystore2/src/db_utils.rs
@@ -0,0 +1,52 @@
+// 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::error::Error as KsError;
+use anyhow::{Context, Result};
+use rusqlite::{Row, Rows};
+
+// Takes Rows as returned by a query call on prepared statement.
+// Extracts exactly one row with the `row_extractor` and fails if more
+// rows are available.
+// If no row was found, `None` is passed to the `row_extractor`.
+// This allows the row extractor to decide on an error condition or
+// a different default behavior.
+pub fn with_rows_extract_one<'a, T, F>(rows: &mut Rows<'a>, row_extractor: F) -> Result<T>
+where
+    F: FnOnce(Option<&Row<'a>>) -> Result<T>,
+{
+    let result =
+        row_extractor(rows.next().context("with_rows_extract_one: Failed to unpack row.")?);
+
+    rows.next()
+        .context("In with_rows_extract_one: Failed to unpack unexpected row.")?
+        .map_or_else(|| Ok(()), |_| Err(KsError::sys()))
+        .context("In with_rows_extract_one: Unexpected row.")?;
+
+    result
+}
+
+pub fn with_rows_extract_all<'a, F>(rows: &mut Rows<'a>, mut row_extractor: F) -> Result<()>
+where
+    F: FnMut(&Row<'a>) -> Result<()>,
+{
+    loop {
+        match rows.next().context("In with_rows_extract_all: Failed to unpack row")? {
+            Some(row) => {
+                row_extractor(&row).context("In with_rows_extract_all.")?;
+            }
+            None => break Ok(()),
+        }
+    }
+}
diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs
index 0654b29..3ef75c8 100644
--- a/keystore2/src/globals.rs
+++ b/keystore2/src/globals.rs
@@ -25,5 +25,12 @@
     /// used by only one thread. So we store one database connection per
     /// thread in this thread local key.
     pub static DB: RefCell<KeystoreDB> =
-            RefCell::new(KeystoreDB::new().expect("Failed to open database."));
+            RefCell::new(
+                KeystoreDB::new(
+                    // Keystore changes to the database directory on startup
+                    // (see keystor2_main.rs).
+                    &std::env::current_dir()
+                    .expect("Could not get the current working directory.")
+                )
+                .expect("Failed to open database."));
 }
diff --git a/keystore2/src/keystore2_main.rs b/keystore2/src/keystore2_main.rs
index ab00794..2916549 100644
--- a/keystore2/src/keystore2_main.rs
+++ b/keystore2/src/keystore2_main.rs
@@ -37,6 +37,9 @@
 
     let mut args = std::env::args();
     args.next().expect("That's odd. How is there not even a first argument?");
+
+    // Keystore changes to the database directory on startup (typically /data/misc/keystore).
+    // For the ground truth check the service startup rule for init (typically in keystore2.rc).
     if let Some(dir) = args.next() {
         if std::env::set_current_dir(dir.clone()).is_err() {
             panic!("Failed to set working directory {}.", dir)
diff --git a/keystore2/src/lib.rs b/keystore2/src/lib.rs
index 067399e..f75ec77 100644
--- a/keystore2/src/lib.rs
+++ b/keystore2/src/lib.rs
@@ -24,3 +24,10 @@
 pub mod security_level;
 pub mod service;
 pub mod utils;
+
+mod db_utils;
+
+#[cfg(test)]
+mod test {
+    pub mod utils;
+}
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index e7d07e3..9a8c7d9 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -52,7 +52,7 @@
     operation_db: OperationDb,
 }
 
-static KEYMINT_SERVICE_NAME: &str = "android.hardware.keymint.IKeyMintDevice";
+static KEYMINT_SERVICE_NAME: &str = "android.hardware.security.keymint.IKeyMintDevice";
 
 // Blob of 32 zeroes used as empty masking key.
 static ZERO_BLOB_32: &[u8] = &[0; 32];
diff --git a/keystore2/src/service.rs b/keystore2/src/service.rs
index eb0d01b..cb04031 100644
--- a/keystore2/src/service.rs
+++ b/keystore2/src/service.rs
@@ -22,10 +22,11 @@
 use crate::error::{self, map_or_log_err, ErrorCode};
 use crate::globals::DB;
 use crate::permission;
-use crate::permission::KeyPerm;
+use crate::permission::{KeyPerm, KeystorePerm};
 use crate::security_level::KeystoreSecurityLevel;
 use crate::utils::{
-    check_grant_permission, check_key_permission, key_parameters_to_authorizations, Asp,
+    check_grant_permission, check_key_permission, check_keystore_permission,
+    key_parameters_to_authorizations, Asp,
 };
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
 use android_system_keystore2::aidl::android::system::keystore2::{
@@ -35,6 +36,8 @@
 };
 use anyhow::{anyhow, Context, Result};
 use binder::{IBinder, Interface, ThreadState};
+use error::Error;
+use keystore2_selinux as selinux;
 
 /// Implementation of the IKeystoreService.
 pub struct KeystoreService {
@@ -146,8 +149,44 @@
     }
 
     fn list_entries(&self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
-        // TODO implement.
-        Err(anyhow!(error::Error::sys()))
+        let mut k = match domain {
+            Domain::APP => KeyDescriptor {
+                domain,
+                nspace: ThreadState::get_calling_uid() as u64 as i64,
+                ..Default::default()
+            },
+            Domain::SELINUX => KeyDescriptor{domain, nspace: namespace, ..Default::default()},
+            _ => return Err(Error::perm()).context(
+                "In list_entries: List entries is only supported for Domain::APP and Domain::SELINUX."
+            ),
+        };
+
+        // First we check if the caller has the info permission for the selected domain/namespace.
+        // By default we use the calling uid as namespace if domain is Domain::APP.
+        // If the first check fails we check if the caller has the list permission allowing to list
+        // any namespace. In that case we also adjust the queried namespace if a specific uid was
+        // selected.
+        match check_key_permission(KeyPerm::get_info(), &k, &None) {
+            Err(e) => {
+                if let Some(selinux::Error::PermissionDenied) =
+                    e.root_cause().downcast_ref::<selinux::Error>()
+                {
+                    check_keystore_permission(KeystorePerm::list())
+                        .context("In list_entries: While checking keystore permission.")?;
+                    if namespace != -1 {
+                        k.nspace = namespace;
+                    }
+                } else {
+                    return Err(e).context("In list_entries: While checking key permission.")?;
+                }
+            }
+            Ok(()) => {}
+        };
+
+        DB.with(|db| {
+            let mut db = db.borrow_mut();
+            db.list(k.domain, k.nspace)
+        })
     }
 
     fn delete_key(&self, key: &KeyDescriptor) -> Result<()> {
diff --git a/keystore2/src/test/utils.rs b/keystore2/src/test/utils.rs
new file mode 100644
index 0000000..e016ec0
--- /dev/null
+++ b/keystore2/src/test/utils.rs
@@ -0,0 +1,63 @@
+// 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 std::env::temp_dir;
+use std::fs::{create_dir, remove_dir_all};
+use std::io::ErrorKind;
+use std::path::Path;
+
+#[derive(Debug)]
+pub struct TempDir {
+    path: std::path::PathBuf,
+    do_drop: bool,
+}
+
+impl TempDir {
+    pub fn new(prefix: &str) -> std::io::Result<Self> {
+        let tmp = loop {
+            let mut tmp = temp_dir();
+            let number: u16 = rand::random();
+            tmp.push(format!("{}_{:05}", prefix, number));
+            match create_dir(&tmp) {
+                Err(e) => match e.kind() {
+                    ErrorKind::AlreadyExists => continue,
+                    _ => return Err(e),
+                },
+                Ok(()) => break tmp,
+            }
+        };
+        Ok(Self { path: tmp, do_drop: true })
+    }
+
+    pub fn path(&self) -> &Path {
+        &self.path
+    }
+
+    /// When a test is failing you can set this to false in order to inspect
+    /// the directory structure after the test failed.
+    #[allow(dead_code)]
+    pub fn do_not_drop(&mut self) {
+        println!("Disabled automatic cleanup for: {:?}", self.path);
+        log::info!("Disabled automatic cleanup for: {:?}", self.path);
+        self.do_drop = false;
+    }
+}
+
+impl Drop for TempDir {
+    fn drop(&mut self) {
+        if self.do_drop {
+            remove_dir_all(&self.path).expect("Cannot delete temporary dir.");
+        }
+    }
+}