Merge "Don't pass Tag::INCLUDE_UNIQUE_ID to attestKey"
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index 02ef408..7713618 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -2114,11 +2114,12 @@
         let tx = self.conn.unchecked_transaction().context(
             "In retrieve_attestation_key_and_cert_chain: Failed to initialize transaction.",
         )?;
-        let key_id: i64;
-        match self.query_kid_for_attestation_key_and_cert_chain(&tx, domain, namespace, km_uuid)? {
+        let key_id: i64 = match self
+            .query_kid_for_attestation_key_and_cert_chain(&tx, domain, namespace, km_uuid)?
+        {
             None => return Ok(None),
-            Some(kid) => key_id = kid,
-        }
+            Some(kid) => kid,
+        };
         tx.commit()
             .context("In retrieve_attestation_key_and_cert_chain: Failed to commit keyid query")?;
         let key_id_guard = KEY_ID_LOCK.get(key_id);
@@ -3667,13 +3668,13 @@
             namespace_del1,
             &KEYSTORE_UUID,
         )?;
-        assert!(!cert_chain.is_some());
+        assert!(cert_chain.is_none());
         cert_chain = db.retrieve_attestation_key_and_cert_chain(
             Domain::APP,
             namespace_del2,
             &KEYSTORE_UUID,
         )?;
-        assert!(!cert_chain.is_some());
+        assert!(cert_chain.is_none());
 
         // Give the garbage collector half a second to catch up.
         std::thread::sleep(Duration::from_millis(500));
diff --git a/keystore2/src/km_compat/km_compat.cpp b/keystore2/src/km_compat/km_compat.cpp
index 79504cf..192f445 100644
--- a/keystore2/src/km_compat/km_compat.cpp
+++ b/keystore2/src/km_compat/km_compat.cpp
@@ -1419,7 +1419,7 @@
         setNumFreeSlots(15);
     }
 
-    softKeyMintDevice_.reset(CreateKeyMintDevice(KeyMintSecurityLevel::SOFTWARE));
+    softKeyMintDevice_ = CreateKeyMintDevice(KeyMintSecurityLevel::SOFTWARE);
 }
 
 sp<Keymaster> getDevice(KeyMintSecurityLevel securityLevel) {
@@ -1447,7 +1447,7 @@
     static std::shared_ptr<IKeyMintDevice> swDevice;
     std::lock_guard<std::mutex> lock(mutex);
     if (!swDevice) {
-        swDevice.reset(CreateKeyMintDevice(KeyMintSecurityLevel::SOFTWARE));
+        swDevice = CreateKeyMintDevice(KeyMintSecurityLevel::SOFTWARE);
     }
     return swDevice;
 }
diff --git a/keystore2/src/km_compat/lib.rs b/keystore2/src/km_compat/lib.rs
index 8abf2ba..13f7760 100644
--- a/keystore2/src/km_compat/lib.rs
+++ b/keystore2/src/km_compat/lib.rs
@@ -286,7 +286,7 @@
         let operation = begin_result.operation.unwrap();
 
         let update_aad_result = operation.updateAad(
-            &b"foobar".to_vec(),
+            b"foobar".as_ref(),
             None, /* authToken */
             None, /* timestampToken */
         );
@@ -310,7 +310,7 @@
         let operation = begin_result.operation.unwrap();
 
         let update_aad_result = operation.updateAad(
-            &b"foobar".to_vec(),
+            b"foobar".as_ref(),
             None, /* authToken */
             None, /* timestampToken */
         );
diff --git a/keystore2/src/legacy_importer.rs b/keystore2/src/legacy_importer.rs
index 81fb06c..5a64020 100644
--- a/keystore2/src/legacy_importer.rs
+++ b/keystore2/src/legacy_importer.rs
@@ -932,8 +932,7 @@
 
         for (uid, alias) in aliases
             .into_iter()
-            .map(|(uid, aliases)| aliases.into_iter().map(move |alias| (uid, alias)))
-            .flatten()
+            .flat_map(|(uid, aliases)| aliases.into_iter().map(move |alias| (uid, alias)))
         {
             let (km_blob_params, _, _) = self
                 .legacy_loader
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index 8574244..1f6be32 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -132,8 +132,7 @@
                 _ => Some(
                     certificate_chain
                         .iter()
-                        .map(|c| c.encodedCertificate.iter())
-                        .flatten()
+                        .flat_map(|c| c.encodedCertificate.iter())
                         .copied()
                         .collect(),
                 ),
diff --git a/keystore2/src/super_key.rs b/keystore2/src/super_key.rs
index 376d44a..74e3e56 100644
--- a/keystore2/src/super_key.rs
+++ b/keystore2/src/super_key.rs
@@ -767,12 +767,8 @@
                     "Failed to super encrypt with LskfBound key."
                 )),
             SuperEncryptionType::ScreenLockBound => {
-                let entry = self
-                    .data
-                    .user_keys
-                    .get(&user_id)
-                    .map(|e| e.screen_lock_bound.as_ref())
-                    .flatten();
+                let entry =
+                    self.data.user_keys.get(&user_id).and_then(|e| e.screen_lock_bound.as_ref());
                 if let Some(super_key) = entry {
                     Self::encrypt_with_aes_super_key(key_blob, super_key).context(concat!(
                         "In handle_super_encryption_on_key_init. ",
diff --git a/keystore2/test_utils/run_as.rs b/keystore2/test_utils/run_as.rs
index d42303d..2485ab5 100644
--- a/keystore2/test_utils/run_as.rs
+++ b/keystore2/test_utils/run_as.rs
@@ -30,9 +30,11 @@
 use nix::sys::wait::{waitpid, WaitStatus};
 use nix::unistd::{
     close, fork, pipe as nix_pipe, read as nix_read, setgid, setuid, write as nix_write,
-    ForkResult, Gid, Uid,
+    ForkResult, Gid, Pid, Uid,
 };
 use serde::{de::DeserializeOwned, Serialize};
+use std::io::{Read, Write};
+use std::marker::PhantomData;
 use std::os::unix::io::RawFd;
 
 fn transition(se_context: selinux::Context, uid: Uid, gid: Gid) {
@@ -48,17 +50,10 @@
 /// reads from the pipe into an expending vector, until no more data can be read.
 struct PipeReader(RawFd);
 
-impl PipeReader {
-    pub fn read_all(&self) -> Result<Vec<u8>, nix::Error> {
-        let mut buffer = [0u8; 128];
-        let mut result = Vec::<u8>::new();
-        loop {
-            let bytes = nix_read(self.0, &mut buffer)?;
-            if bytes == 0 {
-                return Ok(result);
-            }
-            result.extend_from_slice(&buffer[0..bytes]);
-        }
+impl Read for PipeReader {
+    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+        let bytes = nix_read(self.0, buf)?;
+        Ok(bytes)
     }
 }
 
@@ -73,46 +68,264 @@
 /// writes the given buffer into the pipe, returning the number of bytes written.
 struct PipeWriter(RawFd);
 
-impl PipeWriter {
-    pub fn write(&self, data: &[u8]) -> Result<usize, nix::Error> {
-        nix_write(self.0, data)
-    }
-}
-
 impl Drop for PipeWriter {
     fn drop(&mut self) {
         close(self.0).expect("Failed to close writer pipe fd.");
     }
 }
 
+impl Write for PipeWriter {
+    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+        let written = nix_write(self.0, buf)?;
+        Ok(written)
+    }
+
+    fn flush(&mut self) -> std::io::Result<()> {
+        // Flush is a NO-OP.
+        Ok(())
+    }
+}
+
+/// Denotes the sender side of a serializing channel.
+pub struct ChannelWriter<T: Serialize + DeserializeOwned>(PipeWriter, PhantomData<T>);
+
+impl<T: Serialize + DeserializeOwned> ChannelWriter<T> {
+    /// Sends a serializable object to a the corresponding ChannelReader.
+    /// Sending is always non blocking. Panics if any error occurs during io or serialization.
+    pub fn send(&mut self, value: &T) {
+        let serialized = serde_cbor::to_vec(value)
+            .expect("In ChannelWriter::send: Failed to serialize to vector.");
+        let size = serialized.len().to_be_bytes();
+        match self.0.write(&size).expect("In ChannelWriter::send: Failed to write serialized size.")
+        {
+            w if w != std::mem::size_of::<usize>() => {
+                panic!(
+                    "In ChannelWriter::send: Failed to write serialized size. (written: {}).",
+                    w
+                );
+            }
+            _ => {}
+        };
+        match self
+            .0
+            .write(&serialized)
+            .expect("In ChannelWriter::send: Failed to write serialized data.")
+        {
+            w if w != serialized.len() => {
+                panic!(
+                    "In ChannelWriter::send: Failed to write serialized data. (written: {}).",
+                    w
+                );
+            }
+            _ => {}
+        };
+    }
+}
+
+/// Represents the receiving and of a serializing channel.
+pub struct ChannelReader<T>(PipeReader, PhantomData<T>);
+
+impl<T: Serialize + DeserializeOwned> ChannelReader<T> {
+    /// Receives a serializable object from the corresponding ChannelWriter.
+    /// Receiving blocks until an object of type T has been read from the channel.
+    /// Panics if an error occurs during io or deserialization.
+    pub fn recv(&mut self) -> T {
+        let mut size_buffer = [0u8; std::mem::size_of::<usize>()];
+        match self.0.read(&mut size_buffer).expect("In ChannelReader::recv: Failed to read size.") {
+            r if r != size_buffer.len() => {
+                panic!("In ChannelReader::recv: Failed to read size. Insufficient data: {}", r);
+            }
+            _ => {}
+        };
+        let size = usize::from_be_bytes(size_buffer);
+        let mut data_buffer = vec![0u8; size];
+        match self
+            .0
+            .read(&mut data_buffer)
+            .expect("In ChannelReader::recv: Failed to read serialized data.")
+        {
+            r if r != data_buffer.len() => {
+                panic!(
+                    "In ChannelReader::recv: Failed to read serialized data. Insufficient data: {}",
+                    r
+                );
+            }
+            _ => {}
+        };
+
+        serde_cbor::from_slice(&data_buffer)
+            .expect("In ChannelReader::recv: Failed to deserialize data.")
+    }
+}
+
 fn pipe() -> Result<(PipeReader, PipeWriter), nix::Error> {
     let (read_fd, write_fd) = nix_pipe()?;
     Ok((PipeReader(read_fd), PipeWriter(write_fd)))
 }
 
+fn pipe_channel<T>() -> Result<(ChannelReader<T>, ChannelWriter<T>), nix::Error>
+where
+    T: Serialize + DeserializeOwned,
+{
+    let (reader, writer) = pipe()?;
+    Ok((
+        ChannelReader::<T>(reader, Default::default()),
+        ChannelWriter::<T>(writer, Default::default()),
+    ))
+}
+
+/// Handle for handling child processes.
+pub struct ChildHandle<R: Serialize + DeserializeOwned, M: Serialize + DeserializeOwned> {
+    pid: Pid,
+    result_reader: ChannelReader<R>,
+    cmd_writer: ChannelWriter<M>,
+    response_reader: ChannelReader<M>,
+    exit_status: Option<WaitStatus>,
+}
+
+impl<R: Serialize + DeserializeOwned, M: Serialize + DeserializeOwned> ChildHandle<R, M> {
+    /// Send a command message to the child.
+    pub fn send(&mut self, data: &M) {
+        self.cmd_writer.send(data)
+    }
+
+    /// Receive a response from the child.
+    pub fn recv(&mut self) -> M {
+        self.response_reader.recv()
+    }
+
+    /// Get child result. Panics if the child did not exit with status 0 or if a serialization
+    /// error occurred.
+    pub fn get_result(mut self) -> R {
+        let status =
+            waitpid(self.pid, None).expect("ChildHandle::wait: Failed while waiting for child.");
+        match status {
+            WaitStatus::Exited(pid, 0) => {
+                // Child exited successfully.
+                // Read the result from the pipe.
+                self.exit_status = Some(WaitStatus::Exited(pid, 0));
+                self.result_reader.recv()
+            }
+            WaitStatus::Exited(pid, c) => {
+                panic!("Child did not exit as expected: {:?}", WaitStatus::Exited(pid, c));
+            }
+            status => {
+                panic!("Child did not exit at all: {:?}", status);
+            }
+        }
+    }
+}
+
+impl<R: Serialize + DeserializeOwned, M: Serialize + DeserializeOwned> Drop for ChildHandle<R, M> {
+    fn drop(&mut self) {
+        if self.exit_status.is_none() {
+            panic!("Child result not checked.")
+        }
+    }
+}
+
+/// Run the given closure in a new process running with the new identity given as
+/// `uid`, `gid`, and `se_context`. Parent process will run without waiting for child status.
+///
+/// # Safety
+/// run_as_child runs the given closure in the client branch of fork. And it uses non
+/// async signal safe API. This means that calling this function in a multi threaded program
+/// yields undefined behavior in the child. As of this writing, it is safe to call this function
+/// from a Rust device test, because every test itself is spawned as a separate process.
+///
+/// # Safety Binder
+/// It is okay for the closure to use binder services, however, this does not work
+/// if the parent initialized libbinder already. So do not use binder outside of the closure
+/// in your test.
+pub unsafe fn run_as_child<F, R, M>(
+    se_context: &str,
+    uid: Uid,
+    gid: Gid,
+    f: F,
+) -> Result<ChildHandle<R, M>, nix::Error>
+where
+    R: Serialize + DeserializeOwned,
+    M: Serialize + DeserializeOwned,
+    F: 'static + Send + FnOnce(&mut ChannelReader<M>, &mut ChannelWriter<M>) -> R,
+{
+    let se_context =
+        selinux::Context::new(se_context).expect("Unable to construct selinux::Context.");
+    let (result_reader, mut result_writer) = pipe_channel().expect("Failed to create pipe.");
+    let (mut cmd_reader, cmd_writer) = pipe_channel().expect("Failed to create cmd pipe.");
+    let (response_reader, mut response_writer) =
+        pipe_channel().expect("Failed to create cmd pipe.");
+
+    match fork() {
+        Ok(ForkResult::Parent { child, .. }) => {
+            drop(response_writer);
+            drop(cmd_reader);
+            drop(result_writer);
+
+            Ok(ChildHandle::<R, M> {
+                pid: child,
+                result_reader,
+                response_reader,
+                cmd_writer,
+                exit_status: None,
+            })
+        }
+        Ok(ForkResult::Child) => {
+            drop(cmd_writer);
+            drop(response_reader);
+            drop(result_reader);
+
+            // This will panic on error or insufficient privileges.
+            transition(se_context, uid, gid);
+
+            // Run the closure.
+            let result = f(&mut cmd_reader, &mut response_writer);
+
+            // Serialize the result of the closure.
+            result_writer.send(&result);
+
+            // Set exit status to `0`.
+            std::process::exit(0);
+        }
+        Err(errno) => {
+            panic!("Failed to fork: {:?}", errno);
+        }
+    }
+}
+
 /// Run the given closure in a new process running with the new identity given as
 /// `uid`, `gid`, and `se_context`.
-pub fn run_as<F, R>(se_context: &str, uid: Uid, gid: Gid, f: F) -> R
+///
+/// # Safety
+/// run_as runs the given closure in the client branch of fork. And it uses non
+/// async signal safe API. This means that calling this function in a multi threaded program
+/// yields undefined behavior in the child. As of this writing, it is safe to call this function
+/// from a Rust device test, because every test itself is spawned as a separate process.
+///
+/// # Safety Binder
+/// It is okay for the closure to use binder services, however, this does not work
+/// if the parent initialized libbinder already. So do not use binder outside of the closure
+/// in your test.
+pub unsafe fn run_as<F, R>(se_context: &str, uid: Uid, gid: Gid, f: F) -> R
 where
     R: Serialize + DeserializeOwned,
     F: 'static + Send + FnOnce() -> R,
 {
     let se_context =
         selinux::Context::new(se_context).expect("Unable to construct selinux::Context.");
-    let (reader, writer) = pipe().expect("Failed to create pipe.");
+    let (mut reader, mut writer) = pipe_channel::<R>().expect("Failed to create pipe.");
 
-    match unsafe { fork() } {
+    match fork() {
         Ok(ForkResult::Parent { child, .. }) => {
             drop(writer);
             let status = waitpid(child, None).expect("Failed while waiting for child.");
             if let WaitStatus::Exited(_, 0) = status {
                 // Child exited successfully.
                 // Read the result from the pipe.
-                let serialized_result =
-                    reader.read_all().expect("Failed to read result from child.");
+                // let serialized_result =
+                //     reader.read_all().expect("Failed to read result from child.");
 
                 // Deserialize the result and return it.
-                serde_cbor::from_slice(&serialized_result).expect("Failed to deserialize result.")
+                reader.recv()
             } else {
                 panic!("Child did not exit as expected {:?}", status);
             }
@@ -125,10 +338,7 @@
             let result = f();
 
             // Serialize the result of the closure.
-            let vec = serde_cbor::to_vec(&result).expect("Result serialization failed");
-
-            // Send the result to the parent using the pipe.
-            writer.write(&vec).expect("Failed to send serialized result to parent.");
+            writer.send(&result);
 
             // Set exit status to `0`.
             std::process::exit(0);
@@ -151,9 +361,13 @@
     #[test]
     #[should_panic]
     fn test_run_as_panics_on_closure_panic() {
-        run_as(selinux::getcon().unwrap().to_str().unwrap(), getuid(), getgid(), || {
-            panic!("Closure must panic.")
-        });
+        // Safety: run_as must be called from a single threaded process.
+        // This device test is run as a separate single threaded process.
+        unsafe {
+            run_as(selinux::getcon().unwrap().to_str().unwrap(), getuid(), getgid(), || {
+                panic!("Closure must panic.")
+            })
+        };
     }
 
     static TARGET_UID: Uid = Uid::from_raw(10020);
@@ -163,11 +377,15 @@
     /// Tests that the closure is running as the target identity.
     #[test]
     fn test_transition_to_untrusted_app() {
-        run_as(TARGET_CTX, TARGET_UID, TARGET_GID, || {
-            assert_eq!(TARGET_UID, getuid());
-            assert_eq!(TARGET_GID, getgid());
-            assert_eq!(TARGET_CTX, selinux::getcon().unwrap().to_str().unwrap());
-        });
+        // Safety: run_as must be called from a single threaded process.
+        // This device test is run as a separate single threaded process.
+        unsafe {
+            run_as(TARGET_CTX, TARGET_UID, TARGET_GID, || {
+                assert_eq!(TARGET_UID, getuid());
+                assert_eq!(TARGET_GID, getgid());
+                assert_eq!(TARGET_CTX, selinux::getcon().unwrap().to_str().unwrap());
+            })
+        };
     }
 
     #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
@@ -185,7 +403,72 @@
             c: "supercalifragilisticexpialidocious".to_owned(),
         };
         let test_result_clone = test_result.clone();
-        let result = run_as(TARGET_CTX, TARGET_UID, TARGET_GID, || test_result_clone);
+        // Safety: run_as must be called from a single threaded process.
+        // This device test is run as a separate single threaded process.
+        let result = unsafe { run_as(TARGET_CTX, TARGET_UID, TARGET_GID, || test_result_clone) };
         assert_eq!(test_result, result);
     }
+
+    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+    enum PingPong {
+        Ping,
+        Pong,
+    }
+
+    /// Tests that closure is running under given user identity and communicates with calling
+    /// process using pipe.
+    #[test]
+    fn test_run_as_child() {
+        let test_result = SomeResult {
+            a: 5,
+            b: 0xffffffffffffffff,
+            c: "supercalifragilisticexpialidocious".to_owned(),
+        };
+        let test_result_clone = test_result.clone();
+
+        // Safety: run_as_child must be called from a single threaded process.
+        // This device test is run as a separate single threaded process.
+        let mut child_handle: ChildHandle<SomeResult, PingPong> = unsafe {
+            run_as_child(TARGET_CTX, TARGET_UID, TARGET_GID, |cmd_reader, response_writer| {
+                assert_eq!(TARGET_UID, getuid());
+                assert_eq!(TARGET_GID, getgid());
+                assert_eq!(TARGET_CTX, selinux::getcon().unwrap().to_str().unwrap());
+
+                let ping: PingPong = cmd_reader.recv();
+                assert_eq!(ping, PingPong::Ping);
+
+                response_writer.send(&PingPong::Pong);
+
+                let ping: PingPong = cmd_reader.recv();
+                assert_eq!(ping, PingPong::Ping);
+                let pong: PingPong = cmd_reader.recv();
+                assert_eq!(pong, PingPong::Pong);
+
+                response_writer.send(&PingPong::Pong);
+                response_writer.send(&PingPong::Ping);
+
+                test_result_clone
+            })
+            .unwrap()
+        };
+
+        // Send one ping.
+        child_handle.send(&PingPong::Ping);
+
+        // Expect one pong.
+        let pong = child_handle.recv();
+        assert_eq!(pong, PingPong::Pong);
+
+        // Send ping and pong.
+        child_handle.send(&PingPong::Ping);
+        child_handle.send(&PingPong::Pong);
+
+        // Expect pong and ping.
+        let pong = child_handle.recv();
+        assert_eq!(pong, PingPong::Pong);
+        let ping = child_handle.recv();
+        assert_eq!(ping, PingPong::Ping);
+
+        assert_eq!(child_handle.get_result(), test_result);
+    }
 }
diff --git a/ondevice-signing/VerityUtils.cpp b/ondevice-signing/VerityUtils.cpp
index 8ea0727..cd9a1ea 100644
--- a/ondevice-signing/VerityUtils.cpp
+++ b/ondevice-signing/VerityUtils.cpp
@@ -26,6 +26,7 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 #include <asm/byteorder.h>
@@ -125,6 +126,19 @@
         }
     }
 };
+
+static Result<void> measureFsVerity(int fd, const fsverity_digest* digest) {
+    if (ioctl(fd, FS_IOC_MEASURE_VERITY, digest) != 0) {
+        if (errno == ENODATA) {
+            return Error() << "File is not in fs-verity";
+        } else {
+            return ErrnoError() << "Failed to FS_IOC_MEASURE_VERITY";
+        }
+    }
+
+    return {};
+}
+
 }  // namespace
 
 template <typename T> using trailing_unique_ptr = std::unique_ptr<T, DeleteAsPODArray<T>>;
@@ -198,14 +212,12 @@
 static Result<std::string> isFileInVerity(int fd) {
     auto d = makeUniqueWithTrailingData<fsverity_digest>(FS_VERITY_MAX_DIGEST_SIZE);
     d->digest_size = FS_VERITY_MAX_DIGEST_SIZE;
-    auto ret = ioctl(fd, FS_IOC_MEASURE_VERITY, d.get());
-    if (ret < 0) {
-        if (errno == ENODATA) {
-            return Error() << "File is not in fs-verity";
-        } else {
-            return ErrnoError() << "Failed to FS_IOC_MEASURE_VERITY";
-        }
+
+    const auto& status = measureFsVerity(fd, d.get());
+    if (!status.ok()) {
+        return status.error();
     }
+
     return toHex({&d->digest[0], &d->digest[d->digest_size]});
 }
 
@@ -256,6 +268,31 @@
     return digests;
 }
 
+Result<void> enableFsVerity(const std::string& path, const std::string& signature_path) {
+    unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
+    if (!fd.ok()) {
+        return Error() << "Can't open " << path;
+    }
+
+    std::string signature;
+    android::base::ReadFileToString(signature_path, &signature);
+    std::vector<uint8_t> span = std::vector<uint8_t>(signature.begin(), signature.end());
+
+    const auto& enable = enableFsVerity(fd.get(), span);
+    if (!enable.ok()) {
+        return enable.error();
+    }
+
+    auto digest = makeUniqueWithTrailingData<fsverity_digest>(FS_VERITY_MAX_DIGEST_SIZE);
+    digest->digest_size = FS_VERITY_MAX_DIGEST_SIZE;
+    const auto& measure = measureFsVerity(fd.get(), digest.get());
+    if (!measure.ok()) {
+        return measure.error();
+    }
+
+    return {};
+}
+
 Result<std::map<std::string, std::string>> verifyAllFilesInVerity(const std::string& path) {
     std::map<std::string, std::string> digests;
     std::error_code ec;
diff --git a/ondevice-signing/include/VerityUtils.h b/ondevice-signing/include/VerityUtils.h
index 0650563..e6e49c7 100644
--- a/ondevice-signing/include/VerityUtils.h
+++ b/ondevice-signing/include/VerityUtils.h
@@ -36,6 +36,10 @@
 android::base::Result<std::map<std::string, std::string>>
 addFilesToVerityRecursive(const std::string& path, const SigningKey& key);
 
+// Enable verity on the provided file, using the given PKCS7 signature.
+android::base::Result<void> enableFsVerity(const std::string& path,
+                                           const std::string& signature_path);
+
 android::base::Result<void>
 verifyAllFilesUsingCompOs(const std::string& directory_path,
                           const std::map<std::string, std::string>& digests,
diff --git a/ondevice-signing/odsign_main.cpp b/ondevice-signing/odsign_main.cpp
index 7be8b51..fc55846 100644
--- a/ondevice-signing/odsign_main.cpp
+++ b/ondevice-signing/odsign_main.cpp
@@ -205,7 +205,7 @@
     for (const auto& path_digest : digests) {
         auto path = path_digest.first;
         auto digest = path_digest.second;
-        if ((trusted_digests.count(path) == 0)) {
+        if (trusted_digests.count(path) == 0) {
             return Error() << "Couldn't find digest for " << path;
         }
         if (trusted_digests.at(path) != digest) {
@@ -240,7 +240,7 @@
     return verifyDigests(*result, trusted_digests);
 }
 
-Result<OdsignInfo> getOdsignInfo(const SigningKey& key) {
+Result<OdsignInfo> getAndVerifyOdsignInfo(const SigningKey& key) {
     std::string persistedSignature;
     OdsignInfo odsignInfo;
 
@@ -274,6 +274,28 @@
     return odsignInfo;
 }
 
+std::map<std::string, std::string> getTrustedDigests(const SigningKey& key) {
+    std::map<std::string, std::string> trusted_digests;
+
+    if (access(kOdsignInfo.c_str(), F_OK) != 0) {
+        // no odsign info file, which is not necessarily an error - just return
+        // an empty list of digests.
+        LOG(INFO) << kOdsignInfo << " not found.";
+        return trusted_digests;
+    }
+    auto signInfo = getAndVerifyOdsignInfo(key);
+
+    if (signInfo.ok()) {
+        trusted_digests.insert(signInfo->file_hashes().begin(), signInfo->file_hashes().end());
+    } else {
+        // This is not expected, since the file did exist. Log an error and
+        // return an empty list of digests.
+        LOG(ERROR) << "Couldn't load trusted digests: " << signInfo.error();
+    }
+
+    return trusted_digests;
+}
+
 Result<void> persistDigests(const std::map<std::string, std::string>& digests,
                             const SigningKey& key) {
     OdsignInfo signInfo;
@@ -299,23 +321,8 @@
     return {};
 }
 
-Result<void> verifyArtifacts(const SigningKey& key, bool supportsFsVerity) {
-    auto signInfo = getOdsignInfo(key);
-    // Tell init we're done with the key; this is a boot time optimization
-    // in particular for the no fs-verity case, where we need to do a
-    // costly verification. If the files haven't been tampered with, which
-    // should be the common path, the verification will succeed, and we won't
-    // need the key anymore. If it turns out the artifacts are invalid (eg not
-    // in fs-verity) or the hash doesn't match, we won't be able to generate
-    // new artifacts without the key, so in those cases, remove the artifacts,
-    // and use JIT zygote for the current boot. We should recover automatically
-    // by the next boot.
-    SetProperty(kOdsignKeyDoneProp, "1");
-    if (!signInfo.ok()) {
-        return signInfo.error();
-    }
-    std::map<std::string, std::string> trusted_digests(signInfo->file_hashes().begin(),
-                                                       signInfo->file_hashes().end());
+Result<void> verifyArtifactsIntegrity(const std::map<std::string, std::string>& trusted_digests,
+                                      bool supportsFsVerity) {
     Result<void> integrityStatus;
 
     if (supportsFsVerity) {
@@ -361,7 +368,8 @@
 art::odrefresh::ExitCode checkCompOsPendingArtifacts(const SigningKey& signing_key,
                                                      bool* digests_verified) {
     if (!directoryHasContent(kCompOsPendingArtifactsDir)) {
-        return art::odrefresh::ExitCode::kCompilationRequired;
+        // No pending CompOS artifacts, all that matters is the current ones.
+        return checkArtifacts();
     }
 
     // CompOS has generated some artifacts that may, or may not, match the
@@ -406,9 +414,17 @@
         } else {
             LOG(INFO) << "CompOS artifacts successfully verified.";
             odrefresh_status = checkArtifacts();
-            if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
-                // We have digests of all the files, and they aren't going to change, so
-                // we can just sign them & save them now, and skip checking them later.
+            switch (odrefresh_status) {
+            case art::odrefresh::ExitCode::kCompilationRequired:
+                // We have verified all the files, and we need to make sure
+                // we don't check them against odsign.info which will be out
+                // of date.
+                *digests_verified = true;
+                return odrefresh_status;
+            case art::odrefresh::ExitCode::kOkay: {
+                // We have digests of all the files, so we can just sign them & save them now.
+                // We need to make sure we don't check them against odsign.info which will
+                // be out of date.
                 auto persisted = persistDigests(compos_digests, signing_key);
                 if (!persisted.ok()) {
                     LOG(ERROR) << persisted.error();
@@ -418,8 +434,11 @@
                 }
                 LOG(INFO) << "Persisted CompOS digests.";
                 *digests_verified = true;
+                return odrefresh_status;
             }
-            return odrefresh_status;
+            default:
+                return odrefresh_status;
+            }
         }
     }
 
@@ -495,33 +514,60 @@
         }
     }
 
-    art::odrefresh::ExitCode odrefresh_status = art::odrefresh::ExitCode::kCompilationRequired;
     bool digests_verified = false;
+    art::odrefresh::ExitCode odrefresh_status =
+        useCompOs ? checkCompOsPendingArtifacts(*key, &digests_verified) : checkArtifacts();
 
-    if (useCompOs) {
-        odrefresh_status = checkCompOsPendingArtifacts(*key, &digests_verified);
+    // The artifacts dir doesn't necessarily need to exist; if the existing
+    // artifacts on the system partition are valid, those can be used.
+    int err = access(kArtArtifactsDir.c_str(), F_OK);
+    // If we receive any error other than ENOENT, be suspicious
+    bool artifactsPresent = (err == 0) || (err < 0 && errno != ENOENT);
+
+    if (artifactsPresent && !digests_verified &&
+        (odrefresh_status == art::odrefresh::ExitCode::kOkay ||
+         odrefresh_status == art::odrefresh::ExitCode::kCompilationRequired)) {
+        // If we haven't verified the digests yet, we need to validate them. We
+        // need to do this both in case the existing artifacts are okay, but
+        // also if odrefresh said that a recompile is required. In the latter
+        // case, odrefresh may use partial compilation, and leave some
+        // artifacts unchanged.
+        auto trusted_digests = getTrustedDigests(*key);
+
+        if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
+            // Tell init we're done with the key; this is a boot time optimization
+            // in particular for the no fs-verity case, where we need to do a
+            // costly verification. If the files haven't been tampered with, which
+            // should be the common path, the verification will succeed, and we won't
+            // need the key anymore. If it turns out the artifacts are invalid (eg not
+            // in fs-verity) or the hash doesn't match, we won't be able to generate
+            // new artifacts without the key, so in those cases, remove the artifacts,
+            // and use JIT zygote for the current boot. We should recover automatically
+            // by the next boot.
+            SetProperty(kOdsignKeyDoneProp, "1");
+        }
+
+        auto verificationResult = verifyArtifactsIntegrity(trusted_digests, supportsFsVerity);
+        if (!verificationResult.ok()) {
+            int num_removed = removeDirectory(kArtArtifactsDir);
+            if (num_removed == 0) {
+                // If we can't remove the bad artifacts, we shouldn't continue, and
+                // instead prevent Zygote from using them (which is taken care of
+                // in the exit handler).
+                LOG(ERROR) << "Failed to remove unknown artifacts.";
+                return -1;
+            }
+        }
     }
 
+    // Now that we verified existing artifacts, compile if we need to.
     if (odrefresh_status == art::odrefresh::ExitCode::kCompilationRequired) {
         odrefresh_status = compileArtifacts(kForceCompilation);
     }
+
     if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
+        // No new artifacts generated, and we verified existing ones above, nothing left to do.
         LOG(INFO) << "odrefresh said artifacts are VALID";
-        if (!digests_verified) {
-            // A post-condition of validating artifacts is that if the ones on /system
-            // are used, kArtArtifactsDir is removed. Conversely, if kArtArtifactsDir
-            // exists, those are artifacts that will be used, and we should verify them.
-            int err = access(kArtArtifactsDir.c_str(), F_OK);
-            // If we receive any error other than ENOENT, be suspicious
-            bool artifactsPresent = (err == 0) || (err < 0 && errno != ENOENT);
-            if (artifactsPresent) {
-                auto verificationResult = verifyArtifacts(*key, supportsFsVerity);
-                if (!verificationResult.ok()) {
-                    LOG(ERROR) << verificationResult.error();
-                    return -1;
-                }
-            }
-        }
     } else if (odrefresh_status == art::odrefresh::ExitCode::kCompilationSuccess ||
                odrefresh_status == art::odrefresh::ExitCode::kCompilationFailed) {
         const bool compiled_all = odrefresh_status == art::odrefresh::ExitCode::kCompilationSuccess;
diff --git a/provisioner/Android.bp b/provisioner/Android.bp
index aac4878..665a9e7 100644
--- a/provisioner/Android.bp
+++ b/provisioner/Android.bp
@@ -47,8 +47,10 @@
     name: "rkp_factory_extraction_tool",
     vendor: true,
     srcs: ["rkp_factory_extraction_tool.cpp"],
+    defaults: [
+        "keymint_use_latest_hal_aidl_ndk_shared",
+    ],
     shared_libs: [
-        "android.hardware.security.keymint-V1-ndk",
         "libbinder",
         "libbinder_ndk",
         "libcrypto",
diff --git a/provisioner/rkp_factory_extraction_tool.cpp b/provisioner/rkp_factory_extraction_tool.cpp
index 9786c3d..0f45531 100644
--- a/provisioner/rkp_factory_extraction_tool.cpp
+++ b/provisioner/rkp_factory_extraction_tool.cpp
@@ -30,6 +30,7 @@
 using aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent;
 using aidl::android::hardware::security::keymint::MacedPublicKey;
 using aidl::android::hardware::security::keymint::ProtectedData;
+using aidl::android::hardware::security::keymint::RpcHardwareInfo;
 using aidl::android::hardware::security::keymint::remote_prov::generateEekChain;
 using aidl::android::hardware::security::keymint::remote_prov::getProdEekChain;
 using aidl::android::hardware::security::keymint::remote_prov::jsonEncodeCsrWithBuild;
@@ -113,10 +114,10 @@
     return certificateRequest;
 }
 
-std::vector<uint8_t> getEekChain() {
+std::vector<uint8_t> getEekChain(uint32_t curve) {
     if (FLAGS_test_mode) {
         const std::vector<uint8_t> kFakeEekId = {'f', 'a', 'k', 'e', 0};
-        auto eekOrErr = generateEekChain(3 /* chainlength */, kFakeEekId);
+        auto eekOrErr = generateEekChain(curve, 3 /* chainlength */, kFakeEekId);
         if (!eekOrErr) {
             std::cerr << "Failed to generate test EEK somehow: " << eekOrErr.message() << std::endl;
             exit(-1);
@@ -128,15 +129,15 @@
         return eek;
     }
 
-    return getProdEekChain();
+    return getProdEekChain(curve);
 }
 
-void writeOutput(const Array& csr) {
+void writeOutput(const std::string instance_name, const Array& csr) {
     if (FLAGS_output_format == kBinaryCsrOutput) {
         auto bytes = csr.encode();
         std::copy(bytes.begin(), bytes.end(), std::ostream_iterator<char>(std::cout));
     } else if (FLAGS_output_format == kBuildPlusCsr) {
-        auto [json, error] = jsonEncodeCsrWithBuild(csr);
+        auto [json, error] = jsonEncodeCsrWithBuild(instance_name, csr);
         if (!error.empty()) {
             std::cerr << "Error JSON encoding the output: " << error;
             exit(1);
@@ -169,9 +170,16 @@
     std::vector<MacedPublicKey> emptyKeys;
     DeviceInfo verifiedDeviceInfo;
     ProtectedData protectedData;
-    ::ndk::ScopedAStatus status = rkp_service->generateCertificateRequest(
-        FLAGS_test_mode, emptyKeys, getEekChain(), challenge, &verifiedDeviceInfo, &protectedData,
-        &keysToSignMac);
+    RpcHardwareInfo hwInfo;
+    ::ndk::ScopedAStatus status = rkp_service->getHardwareInfo(&hwInfo);
+    if (!status.isOk()) {
+        std::cerr << "Failed to get hardware info for '" << fullName
+                  << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
+        exit(-1);
+    }
+    status = rkp_service->generateCertificateRequest(
+        FLAGS_test_mode, emptyKeys, getEekChain(hwInfo.supportedEekCurve), challenge,
+        &verifiedDeviceInfo, &protectedData, &keysToSignMac);
     if (!status.isOk()) {
         std::cerr << "Bundle extraction failed for '" << fullName
                   << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
@@ -179,7 +187,7 @@
     }
     auto request =
         composeCertificateRequest(protectedData, verifiedDeviceInfo, challenge, keysToSignMac);
-    writeOutput(request);
+    writeOutput(std::string(name), request);
 }
 
 }  // namespace