Keystore 2.0: Implement list keys.

Test: keystore2_test
Change-Id: Id5b875adce95723cd837b22beca7af44621bb2cd
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index a2cd6cd..9086faf 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -390,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(())
     }
 
@@ -759,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,
@@ -1465,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.