Sign artifacts after compilation

If compilation succeeds, pass over all the artifacts we generated and
produce an OdsignInfo file with all the names and digests and a
signature of it using the CompOS key.

Various refactorings along the way to make it eaiser:
- Extract the odrefresh ExitCode enum for reuse
- Extracted a Signer, distinct from an ArtifactSigner
- Defined OdrefreshContext to stop the linter complaining about a
  function with >7 arguments.

Also added more debugging to help fix my various silly mistakes.

Bug: 161471326
Test: composd_cmd forced-odrefresh -> signature file produced
Change-Id: Ia6a6abd9e28158f4767e7752727635087f9bb566
diff --git a/compos/common/Android.bp b/compos/common/Android.bp
index 5893fd6..7c61d94 100644
--- a/compos/common/Android.bp
+++ b/compos/common/Android.bp
@@ -14,8 +14,10 @@
         "libbinder_rpc_unstable_bindgen",
         "libbinder_rs",
         "liblog_rust",
+        "libnum_traits",
         "librustutils",
     ],
+    proc_macros: ["libnum_derive"],
     shared_libs: [
         "libbinder_rpc_unstable",
     ],
diff --git a/compos/common/lib.rs b/compos/common/lib.rs
index 9b07030..5c28379 100644
--- a/compos/common/lib.rs
+++ b/compos/common/lib.rs
@@ -17,6 +17,7 @@
 //! Common items used by CompOS server and/or clients
 
 pub mod compos_client;
+pub mod odrefresh;
 pub mod timeouts;
 
 /// Special CID indicating "any".
diff --git a/compos/common/odrefresh.rs b/compos/common/odrefresh.rs
new file mode 100644
index 0000000..7838b69
--- /dev/null
+++ b/compos/common/odrefresh.rs
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+//! Helpers for running odrefresh
+
+use num_derive::FromPrimitive;
+use num_traits::FromPrimitive;
+
+/// The path to the odrefresh binary
+pub const ODREFRESH_PATH: &str = "/apex/com.android.art/bin/odrefresh";
+
+// TODO: What if this changes?
+const EX_MAX: i8 = 78;
+
+/// The defined odrefresh exit codes - see art/odrefresh/include/odrefresh/odrefresh.h
+#[derive(Debug, PartialEq, Eq, FromPrimitive)]
+#[repr(i8)]
+pub enum ExitCode {
+    /// No compilation required, all artifacts look good
+    Okay = 0i8,
+    /// Compilation required
+    CompilationRequired = EX_MAX + 1,
+    /// New artifacts successfully generated
+    CompilationSuccess = EX_MAX + 2,
+    /// Compilation failed
+    CompilationFailed = EX_MAX + 3,
+    /// Removal of existing invalid artifacts failed
+    CleanupFailed = EX_MAX + 4,
+}
+
+impl ExitCode {
+    /// Map an integer to the corresponding ExitCode enum, if there is one
+    pub fn from_i32(exit_code: i32) -> Option<Self> {
+        FromPrimitive::from_i32(exit_code)
+    }
+}
diff --git a/compos/composd/Android.bp b/compos/composd/Android.bp
index 735b9a5..3190395 100644
--- a/compos/composd/Android.bp
+++ b/compos/composd/Android.bp
@@ -20,13 +20,11 @@
         "libcomposd_native_rust",
         "libminijail_rust",
         "libnix",
-        "libnum_traits",
         "liblibc",
         "liblog_rust",
         "librustutils",
         "libshared_child",
     ],
-    proc_macros: ["libnum_derive"],
     apex_available: [
         "com.android.compos",
     ],
diff --git a/compos/composd/src/compilation_task.rs b/compos/composd/src/compilation_task.rs
index 18f5aac..f82a3e9 100644
--- a/compos/composd/src/compilation_task.rs
+++ b/compos/composd/src/compilation_task.rs
@@ -15,12 +15,13 @@
  */
 
 use crate::instance_starter::CompOsInstance;
-use crate::odrefresh::{self, Odrefresh};
+use crate::odrefresh::Odrefresh;
 use android_system_composd::aidl::android::system::composd::{
     ICompilationTask::ICompilationTask, ICompilationTaskCallback::ICompilationTaskCallback,
 };
 use android_system_composd::binder::{Interface, Result as BinderResult, Strong};
 use anyhow::Result;
+use compos_common::odrefresh::ExitCode;
 use log::{error, warn};
 use std::sync::{Arc, Mutex};
 use std::thread;
@@ -91,7 +92,7 @@
             // We don't do the callback if cancel has already happened.
             if let Some(task) = task {
                 let result = match exit_code {
-                    Ok(odrefresh::ExitCode::CompilationSuccess) => task.callback.onSuccess(),
+                    Ok(ExitCode::CompilationSuccess) => task.callback.onSuccess(),
                     Ok(exit_code) => {
                         error!("Unexpected odrefresh result: {:?}", exit_code);
                         task.callback.onFailure()
diff --git a/compos/composd/src/odrefresh.rs b/compos/composd/src/odrefresh.rs
index d6a3435..2cefab0 100644
--- a/compos/composd/src/odrefresh.rs
+++ b/compos/composd/src/odrefresh.rs
@@ -20,10 +20,9 @@
 use anyhow::{bail, Context, Result};
 use compos_aidl_interface::aidl::com::android::compos::ICompOsService::ICompOsService;
 use compos_aidl_interface::binder::Strong;
+use compos_common::odrefresh::{ExitCode, ODREFRESH_PATH};
 use compos_common::timeouts::{need_extra_time, EXTENDED_TIMEOUTS};
 use compos_common::VMADDR_CID_ANY;
-use num_derive::FromPrimitive;
-use num_traits::FromPrimitive;
 use rustutils::system_properties;
 use shared_child::SharedChild;
 use std::fs::{File, OpenOptions};
@@ -32,23 +31,8 @@
 use std::path::Path;
 use std::process::Command;
 
-// TODO: What if this changes?
-const EX_MAX: i8 = 78;
-
-const ODREFRESH_BIN: &str = "/apex/com.android.art/bin/odrefresh";
 const ART_APEX_DATA: &str = "/data/misc/apexdata/com.android.art";
 
-#[derive(Debug, PartialEq, Eq, FromPrimitive)]
-#[repr(i8)]
-pub enum ExitCode {
-    // Copied from art/odrefresh/include/odrefresh/odrefresh.h
-    Okay = 0i8,
-    CompilationRequired = EX_MAX + 1,
-    CompilationSuccess = EX_MAX + 2,
-    CompilationFailed = EX_MAX + 3,
-    CleanupFailed = EX_MAX + 4,
-}
-
 pub struct Odrefresh {
     child: SharedChild,
 }
@@ -64,7 +48,7 @@
 
     fn spawn_odrefresh(target_dir: &str, compile_arg: &str) -> Result<Self> {
         // We don`t need to capture stdout/stderr - odrefresh writes to the log
-        let mut cmdline = Command::new(ODREFRESH_BIN);
+        let mut cmdline = Command::new(ODREFRESH_PATH);
         if need_extra_time()? {
             cmdline
                 .arg(format!(
@@ -87,7 +71,7 @@
     pub fn wait_for_exit(&self) -> Result<ExitCode> {
         // No timeout here - but clients can kill the process, which will end the wait.
         let status = self.child.wait()?;
-        if let Some(exit_code) = status.code().and_then(FromPrimitive::from_i32) {
+        if let Some(exit_code) = status.code().and_then(ExitCode::from_i32) {
             Ok(exit_code)
         } else {
             bail!("odrefresh exited with {}", status)
@@ -122,7 +106,7 @@
     )?;
 
     drop(fd_server_raii);
-    if let Some(exit_code) = FromPrimitive::from_i8(exit_code) {
+    if let Some(exit_code) = ExitCode::from_i32(exit_code.into()) {
         Ok(exit_code)
     } else {
         bail!("odrefresh exited with {}", exit_code)
diff --git a/compos/composd/src/odrefresh_task.rs b/compos/composd/src/odrefresh_task.rs
index 64565dd..262021c 100644
--- a/compos/composd/src/odrefresh_task.rs
+++ b/compos/composd/src/odrefresh_task.rs
@@ -22,6 +22,7 @@
 use android_system_composd::binder::{Interface, Result as BinderResult, Strong};
 use anyhow::Result;
 use compos_aidl_interface::aidl::com::android::compos::ICompOsService::ICompOsService;
+use compos_common::odrefresh::ExitCode;
 use log::{error, warn};
 use std::sync::{Arc, Mutex};
 use std::thread;
@@ -72,7 +73,7 @@
             // We don't do the callback if cancel has already happened.
             if let Some(task) = task {
                 let result = match exit_code {
-                    Ok(odrefresh::ExitCode::CompilationSuccess) => task.callback.onSuccess(),
+                    Ok(ExitCode::CompilationSuccess) => task.callback.onSuccess(),
                     Ok(exit_code) => {
                         error!("Unexpected odrefresh result: {:?}", exit_code);
                         task.callback.onFailure()
diff --git a/compos/src/artifact_signer.rs b/compos/src/artifact_signer.rs
index 54b8d7a..ce32d6b 100644
--- a/compos/src/artifact_signer.rs
+++ b/compos/src/artifact_signer.rs
@@ -19,7 +19,7 @@
 
 #![allow(dead_code)] // Will be used soon
 
-use crate::compos_key_service::CompOsKeyService;
+use crate::compos_key_service::Signer;
 use crate::fsverity;
 use anyhow::{anyhow, Context, Result};
 use odsign_proto::odsign_info::OdsignInfo;
@@ -27,31 +27,25 @@
 use std::fs::File;
 use std::io::Write;
 use std::os::unix::io::AsRawFd;
-use std::path::{Path, PathBuf};
+use std::path::Path;
 
 const TARGET_DIRECTORY: &str = "/data/misc/apexdata/com.android.art/dalvik-cache";
 const SIGNATURE_EXTENSION: &str = ".signature";
 
 /// Accumulates and then signs information about generated artifacts.
 pub struct ArtifactSigner<'a> {
-    key_blob: Vec<u8>,
-    key_service: &'a CompOsKeyService,
-    base_directory: PathBuf,
+    base_directory: &'a Path,
     file_digests: Vec<(String, String)>, // (File name, digest in hex)
 }
 
 impl<'a> ArtifactSigner<'a> {
     /// base_directory specifies the directory under which the artifacts are currently located;
     /// they will eventually be moved under TARGET_DIRECTORY once they are verified and activated.
-    pub fn new(
-        key_blob: Vec<u8>,
-        key_service: &'a CompOsKeyService,
-        base_directory: PathBuf,
-    ) -> Self {
-        ArtifactSigner { key_blob, key_service, base_directory, file_digests: Vec::new() }
+    pub fn new(base_directory: &'a Path) -> Self {
+        Self { base_directory, file_digests: Vec::new() }
     }
 
-    pub fn add_artifact(&mut self, path: PathBuf) -> Result<()> {
+    pub fn add_artifact(&mut self, path: &Path) -> Result<()> {
         // The path we store is where the file will be when it is verified, not where it is now.
         let suffix = path
             .strip_prefix(&self.base_directory)
@@ -59,7 +53,7 @@
         let target_path = Path::new(TARGET_DIRECTORY).join(suffix);
         let target_path = target_path.to_str().ok_or_else(|| anyhow!("Invalid path"))?;
 
-        let file = File::open(&path)?;
+        let file = File::open(path).with_context(|| format!("Opening {}", path.display()))?;
         let digest = fsverity::measure(file.as_raw_fd())?;
         let digest = to_hex_string(&digest);
 
@@ -69,12 +63,12 @@
 
     /// Consume this ArtifactSigner and write details of all its artifacts to the given path,
     /// with accompanying sigature file.
-    pub fn write_info_and_signature(self, info_path: &Path) -> Result<()> {
+    pub fn write_info_and_signature(self, signer: Signer, info_path: &Path) -> Result<()> {
         let mut info = OdsignInfo::new();
         info.mut_file_hashes().extend(self.file_digests.into_iter());
         let bytes = info.write_to_bytes()?;
 
-        let signature = self.key_service.sign(&self.key_blob, &bytes)?;
+        let signature = signer.sign(&bytes)?;
 
         let mut file = File::create(info_path)?;
         file.write_all(&bytes)?;
diff --git a/compos/src/compilation.rs b/compos/src/compilation.rs
index f8a66c2..cf6f30a 100644
--- a/compos/src/compilation.rs
+++ b/compos/src/compilation.rs
@@ -18,10 +18,12 @@
 use log::{debug, error, info};
 use minijail::{self, Minijail};
 use std::env;
-use std::fs::File;
+use std::fs::{read_dir, File};
 use std::os::unix::io::{AsRawFd, RawFd};
 use std::path::{Path, PathBuf};
 
+use crate::artifact_signer::ArtifactSigner;
+use crate::compos_key_service::Signer;
 use crate::fsverity;
 use authfs_aidl_interface::aidl::com::android::virt::fs::{
     AuthFsConfig::{
@@ -34,6 +36,7 @@
 };
 use authfs_aidl_interface::binder::{ParcelFileDescriptor, Strong};
 use compos_aidl_interface::aidl::com::android::compos::FdAnnotation::FdAnnotation;
+use compos_common::odrefresh::ExitCode;
 
 const FD_SERVER_PORT: i32 = 3264; // TODO: support dynamic port
 
@@ -58,28 +61,51 @@
     image: ParcelFileDescriptor,
 }
 
-pub fn odrefresh(
-    odrefresh_path: &Path,
-    target_dir_name: &str,
+pub struct OdrefreshContext<'a> {
     system_dir_fd: i32,
     output_dir_fd: i32,
     staging_dir_fd: i32,
-    zygote_arch: &str,
+    target_dir_name: &'a str,
+    zygote_arch: &'a str,
+}
+
+impl<'a> OdrefreshContext<'a> {
+    pub fn new(
+        system_dir_fd: i32,
+        output_dir_fd: i32,
+        staging_dir_fd: i32,
+        target_dir_name: &'a str,
+        zygote_arch: &'a str,
+    ) -> Result<Self> {
+        if system_dir_fd < 0 || output_dir_fd < 0 || staging_dir_fd < 0 {
+            bail!("The remote FDs are expected to be non-negative");
+        }
+        if zygote_arch != "zygote64" && zygote_arch != "zygote64_32" {
+            bail!("Invalid zygote arch");
+        }
+        Ok(Self { system_dir_fd, output_dir_fd, staging_dir_fd, target_dir_name, zygote_arch })
+    }
+}
+
+pub fn odrefresh(
+    odrefresh_path: &Path,
+    context: OdrefreshContext,
     authfs_service: Strong<dyn IAuthFsService>,
-) -> Result<i8> {
+    signer: Signer,
+) -> Result<ExitCode> {
     // Mount authfs (via authfs_service). The authfs instance unmounts once the `authfs` variable
     // is out of scope.
     let authfs_config = AuthFsConfig {
         port: FD_SERVER_PORT,
         inputDirFdAnnotations: vec![InputDirFdAnnotation {
-            fd: system_dir_fd,
+            fd: context.system_dir_fd,
             // TODO(206869687): Replace /dev/null with the real path when possible.
             manifestPath: "/dev/null".to_string(),
             prefix: "/system".to_string(),
         }],
         outputDirFdAnnotations: vec![
-            OutputDirFdAnnotation { fd: output_dir_fd },
-            OutputDirFdAnnotation { fd: staging_dir_fd },
+            OutputDirFdAnnotation { fd: context.output_dir_fd },
+            OutputDirFdAnnotation { fd: context.staging_dir_fd },
         ],
         ..Default::default()
     };
@@ -87,21 +113,21 @@
     let mountpoint = PathBuf::from(authfs.getMountPoint()?);
 
     let mut android_root = mountpoint.clone();
-    android_root.push(system_dir_fd.to_string());
+    android_root.push(context.system_dir_fd.to_string());
     android_root.push("system");
     env::set_var("ANDROID_ROOT", &android_root);
+    debug!("ANDROID_ROOT={:?}", &android_root);
 
-    let mut art_apex_data = mountpoint.clone();
-    art_apex_data.push(output_dir_fd.to_string());
+    let art_apex_data = mountpoint.join(context.output_dir_fd.to_string());
     env::set_var("ART_APEX_DATA", &art_apex_data);
+    debug!("ART_APEX_DATA={:?}", &art_apex_data);
 
-    let mut staging_dir = mountpoint;
-    staging_dir.push(staging_dir_fd.to_string());
+    let staging_dir = mountpoint.join(context.staging_dir_fd.to_string());
 
     let args = vec![
         "odrefresh".to_string(),
-        format!("--zygote-arch={}", zygote_arch),
-        format!("--dalvik-cache={}", target_dir_name),
+        format!("--zygote-arch={}", context.zygote_arch),
+        format!("--dalvik-cache={}", context.target_dir_name),
         "--no-refresh".to_string(),
         format!("--staging-dir={}", staging_dir.display()),
         "--force-compile".to_string(),
@@ -109,17 +135,47 @@
     debug!("Running odrefresh with args: {:?}", &args);
     let jail = spawn_jailed_task(odrefresh_path, &args, Vec::new() /* fd_mapping */)
         .context("Spawn odrefresh")?;
-    match jail.wait() {
-        // TODO(161471326): On success, sign all files in the output directory.
-        Ok(()) => Ok(0i8),
-        Err(minijail::Error::ReturnCode(exit_code)) => {
-            info!("odrefresh exited with exit code {}", exit_code);
-            Ok(exit_code as i8)
-        }
+    let exit_code = match jail.wait() {
+        Ok(_) => Result::<u8>::Ok(0),
+        Err(minijail::Error::ReturnCode(exit_code)) => Ok(exit_code),
         Err(e) => {
             bail!("Unexpected minijail error: {}", e)
         }
+    }?;
+
+    let exit_code = ExitCode::from_i32(exit_code.into())
+        .ok_or_else(|| anyhow!("Unexpected odrefresh exit code: {}", exit_code))?;
+    info!("odrefresh exited with {:?}", exit_code);
+
+    if exit_code == ExitCode::CompilationSuccess {
+        // authfs only shows us the files we created, so it's ok to just sign everything under
+        // the target directory.
+        let target_dir = art_apex_data.join(context.target_dir_name);
+        let mut artifact_signer = ArtifactSigner::new(&target_dir);
+        add_artifacts(&target_dir, &mut artifact_signer)?;
+
+        artifact_signer.write_info_and_signature(signer, &target_dir.join("compos.info"))?;
     }
+
+    Ok(exit_code)
+}
+
+fn add_artifacts(target_dir: &Path, artifact_signer: &mut ArtifactSigner) -> Result<()> {
+    for entry in
+        read_dir(&target_dir).with_context(|| format!("Traversing {}", target_dir.display()))?
+    {
+        let entry = entry?;
+        let file_type = entry.file_type()?;
+        if file_type.is_dir() {
+            add_artifacts(&entry.path(), artifact_signer)?;
+        } else if file_type.is_file() {
+            artifact_signer.add_artifact(&entry.path())?;
+        } else {
+            // authfs shouldn't create anything else, but just in case
+            bail!("Unexpected file type in artifacts: {:?}", entry);
+        }
+    }
+    Ok(())
 }
 
 /// Runs the compiler with given flags with file descriptors described in `fd_annotation` retrieved
diff --git a/compos/src/compos_key_service.rs b/compos/src/compos_key_service.rs
index f6caac9..086a162 100644
--- a/compos/src/compos_key_service.rs
+++ b/compos/src/compos_key_service.rs
@@ -101,7 +101,7 @@
         let mut data = [0u8; 32];
         self.random.fill(&mut data).context("No random data")?;
 
-        let signature = self.sign(key_blob, &data)?;
+        let signature = self.new_signer(key_blob).sign(&data)?;
 
         let public_key =
             signature::UnparsedPublicKey::new(&signature::RSA_PKCS1_2048_8192_SHA256, public_key);
@@ -110,8 +110,19 @@
         Ok(())
     }
 
-    pub fn sign(&self, key_blob: &[u8], data: &[u8]) -> Result<Vec<u8>> {
-        let key_descriptor = KeyDescriptor { blob: Some(key_blob.to_vec()), ..BLOB_KEY_DESCRIPTOR };
+    pub fn new_signer(&self, key_blob: &[u8]) -> Signer {
+        Signer { key_blob: key_blob.to_vec(), security_level: self.security_level.clone() }
+    }
+}
+
+pub struct Signer {
+    key_blob: Vec<u8>,
+    security_level: Strong<dyn IKeystoreSecurityLevel>,
+}
+
+impl Signer {
+    pub fn sign(self, data: &[u8]) -> Result<Vec<u8>> {
+        let key_descriptor = KeyDescriptor { blob: Some(self.key_blob), ..BLOB_KEY_DESCRIPTOR };
         let operation_parameters = [PURPOSE_SIGN, ALGORITHM, PADDING, DIGEST];
         let forced = false;
 
diff --git a/compos/src/compsvc.rs b/compos/src/compsvc.rs
index 4540cd8..aa4b9bd 100644
--- a/compos/src/compsvc.rs
+++ b/compos/src/compsvc.rs
@@ -26,8 +26,8 @@
 use std::path::PathBuf;
 use std::sync::RwLock;
 
-use crate::compilation::{compile_cmd, odrefresh, CompilerOutput};
-use crate::compos_key_service::CompOsKeyService;
+use crate::compilation::{compile_cmd, odrefresh, CompilerOutput, OdrefreshContext};
+use crate::compos_key_service::{CompOsKeyService, Signer};
 use crate::fsverity;
 use authfs_aidl_interface::aidl::com::android::virt::fs::IAuthFsService::IAuthFsService;
 use compos_aidl_interface::aidl::com::android::compos::{
@@ -39,10 +39,10 @@
 use compos_aidl_interface::binder::{
     BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Strong,
 };
+use compos_common::odrefresh::ODREFRESH_PATH;
 
 const AUTHFS_SERVICE_NAME: &str = "authfs_service";
 const DEX2OAT_PATH: &str = "/apex/com.android.art/bin/dex2oat64";
-const ODREFRESH_PATH: &str = "/apex/com.android.art/bin/odrefresh";
 
 /// Constructs a binder object that implements ICompOsService.
 pub fn new_binder() -> Result<Strong<dyn ICompOsService>> {
@@ -65,14 +65,21 @@
 impl CompOsService {
     fn generate_raw_fsverity_signature(
         &self,
-        key_blob: &[u8],
         fsverity_digest: &fsverity::Sha256Digest,
-    ) -> Vec<u8> {
+    ) -> BinderResult<Vec<u8>> {
         let formatted_digest = fsverity::to_formatted_digest(fsverity_digest);
-        self.key_service.sign(key_blob, &formatted_digest[..]).unwrap_or_else(|e| {
-            warn!("Failed to sign the fsverity digest, returning empty signature.  Error: {}", e);
-            Vec::new()
-        })
+        self.new_signer()?
+            .sign(&formatted_digest[..])
+            .map_err(|e| new_binder_exception(ExceptionCode::SERVICE_SPECIFIC, e.to_string()))
+    }
+
+    fn new_signer(&self) -> BinderResult<Signer> {
+        let key = &*self.key_blob.read().unwrap();
+        if key.is_empty() {
+            Err(new_binder_exception(ExceptionCode::ILLEGAL_STATE, "Key is not initialized"))
+        } else {
+            Ok(self.key_service.new_signer(key))
+        }
     }
 }
 
@@ -110,36 +117,27 @@
         target_dir_name: &str,
         zygote_arch: &str,
     ) -> BinderResult<i8> {
-        if system_dir_fd < 0 || output_dir_fd < 0 || staging_dir_fd < 0 {
-            return Err(new_binder_exception(
-                ExceptionCode::ILLEGAL_ARGUMENT,
-                "The remote FDs are expected to be non-negative",
-            ));
-        }
-        if zygote_arch != "zygote64" && zygote_arch != "zygote64_32" {
-            return Err(new_binder_exception(
-                ExceptionCode::ILLEGAL_ARGUMENT,
-                "Invalid zygote arch",
-            ));
-        }
-
-        let authfs_service = get_authfs_service()?;
-        odrefresh(
-            &self.odrefresh_path,
-            target_dir_name,
+        let context = OdrefreshContext::new(
             system_dir_fd,
             output_dir_fd,
             staging_dir_fd,
+            target_dir_name,
             zygote_arch,
-            authfs_service,
         )
-        .map_err(|e| {
-            warn!("odrefresh failed: {}", e);
-            new_binder_exception(
-                ExceptionCode::SERVICE_SPECIFIC,
-                format!("odrefresh failed: {}", e),
-            )
-        })
+        .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT, e.to_string()))?;
+
+        let authfs_service = get_authfs_service()?;
+        let exit_code =
+            odrefresh(&self.odrefresh_path, context, authfs_service, self.new_signer()?).map_err(
+                |e| {
+                    warn!("odrefresh failed: {:?}", e);
+                    new_binder_exception(
+                        ExceptionCode::SERVICE_SPECIFIC,
+                        format!("odrefresh failed: {}", e),
+                    )
+                },
+            )?;
+        Ok(exit_code as i8)
     }
 
     fn compile_cmd(
@@ -157,23 +155,15 @@
             })?;
         match output {
             CompilerOutput::Digests { oat, vdex, image } => {
-                let key = &*self.key_blob.read().unwrap();
-                if key.is_empty() {
-                    Err(new_binder_exception(
-                        ExceptionCode::ILLEGAL_STATE,
-                        "Key is not initialized",
-                    ))
-                } else {
-                    let oat_signature = self.generate_raw_fsverity_signature(key, &oat);
-                    let vdex_signature = self.generate_raw_fsverity_signature(key, &vdex);
-                    let image_signature = self.generate_raw_fsverity_signature(key, &image);
-                    Ok(CompilationResult {
-                        exitCode: 0,
-                        oatSignature: oat_signature,
-                        vdexSignature: vdex_signature,
-                        imageSignature: image_signature,
-                    })
-                }
+                let oat_signature = self.generate_raw_fsverity_signature(&oat)?;
+                let vdex_signature = self.generate_raw_fsverity_signature(&vdex)?;
+                let image_signature = self.generate_raw_fsverity_signature(&image)?;
+                Ok(CompilationResult {
+                    exitCode: 0,
+                    oatSignature: oat_signature,
+                    vdexSignature: vdex_signature,
+                    imageSignature: image_signature,
+                })
             }
             CompilerOutput::ExitCode(exit_code) => {
                 Ok(CompilationResult { exitCode: exit_code, ..Default::default() })
@@ -201,14 +191,9 @@
     }
 
     fn sign(&self, data: &[u8]) -> BinderResult<Vec<u8>> {
-        let key = &*self.key_blob.read().unwrap();
-        if key.is_empty() {
-            Err(new_binder_exception(ExceptionCode::ILLEGAL_STATE, "Key is not initialized"))
-        } else {
-            self.key_service
-                .sign(key, data)
-                .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))
-        }
+        self.new_signer()?
+            .sign(data)
+            .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))
     }
 }