Merge "Remove odrefresh --verify from ComposTestCase"
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/aidl/android/system/composd/IIsolatedCompilationService.aidl b/compos/composd/aidl/android/system/composd/IIsolatedCompilationService.aidl
index e73963d..ec5f2f5 100644
--- a/compos/composd/aidl/android/system/composd/IIsolatedCompilationService.aidl
+++ b/compos/composd/aidl/android/system/composd/IIsolatedCompilationService.aidl
@@ -55,15 +55,4 @@
* a reference to the ICompilationTask until compilation completes or is cancelled.
*/
ICompilationTask startAsyncOdrefresh(ICompilationTaskCallback callback);
-
- /**
- * Run odrefresh in a test instance of CompOS until completed or failed.
- *
- * This compiles BCP extensions and system server, even if the system artifacts are up to date,
- * and writes the results to a test directory to avoid disrupting any real artifacts in
- * existence.
- *
- * TODO(205750213): Change the API to async.
- */
- byte startTestOdrefresh();
}
diff --git a/compos/composd/src/compilation_task.rs b/compos/composd/src/compilation_task.rs
index 18f5aac..871c4fb 100644
--- a/compos/composd/src/compilation_task.rs
+++ b/compos/composd/src/compilation_task.rs
@@ -15,16 +15,19 @@
*/
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;
+// TODO: Delete
+
#[derive(Clone)]
pub struct CompilationTask {
running_task: Arc<Mutex<Option<RunningTask>>>,
@@ -91,7 +94,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..f06a4b2 100644
--- a/compos/composd/src/odrefresh.rs
+++ b/compos/composd/src/odrefresh.rs
@@ -16,39 +16,15 @@
//! Handle the details of executing odrefresh to generate compiled artifacts.
-use crate::fd_server_helper::FdServerConfig;
+// TODO: Delete
+
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};
-use std::os::unix::fs::OpenOptionsExt;
-use std::os::unix::io::AsRawFd;
-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 +40,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 +63,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)
@@ -98,43 +74,3 @@
self.child.kill().context("Killing odrefresh process failed")
}
}
-
-pub fn run_in_vm(service: Strong<dyn ICompOsService>, target_dir_name: &str) -> Result<ExitCode> {
- let staging_dir = open_dir(composd_native::palette_create_odrefresh_staging_directory()?)?;
- let system_dir = open_dir(Path::new("/system"))?;
- let output_dir = open_dir(Path::new(ART_APEX_DATA))?;
-
- // Spawn a fd_server to serve the FDs.
- let fd_server_config = FdServerConfig {
- ro_dir_fds: vec![system_dir.as_raw_fd()],
- rw_dir_fds: vec![staging_dir.as_raw_fd(), output_dir.as_raw_fd()],
- ..Default::default()
- };
- let fd_server_raii = fd_server_config.into_fd_server()?;
-
- let zygote_arch = system_properties::read("ro.zygote")?;
- let exit_code = service.odrefresh(
- system_dir.as_raw_fd(),
- output_dir.as_raw_fd(),
- staging_dir.as_raw_fd(),
- target_dir_name,
- &zygote_arch,
- )?;
-
- drop(fd_server_raii);
- if let Some(exit_code) = FromPrimitive::from_i8(exit_code) {
- Ok(exit_code)
- } else {
- bail!("odrefresh exited with {}", exit_code)
- }
-}
-
-/// Returns an owned FD of the directory. It currently returns a `File` as a FD owner, but
-/// it's better to use `std::os::unix::io::OwnedFd` once/if it becomes standard.
-fn open_dir(path: &Path) -> Result<File> {
- OpenOptions::new()
- .custom_flags(libc::O_DIRECTORY)
- .read(true) // O_DIRECTORY can only be opened with read
- .open(path)
- .with_context(|| format!("Failed to open {:?} directory as path fd", path))
-}
diff --git a/compos/composd/src/odrefresh_task.rs b/compos/composd/src/odrefresh_task.rs
index 64565dd..9b70248 100644
--- a/compos/composd/src/odrefresh_task.rs
+++ b/compos/composd/src/odrefresh_task.rs
@@ -14,18 +14,28 @@
* limitations under the License.
*/
+//! Handle running odrefresh in the VM, with an async interface to allow cancellation
+
+use crate::fd_server_helper::FdServerConfig;
use crate::instance_starter::CompOsInstance;
-use crate::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 anyhow::{bail, Context, Result};
use compos_aidl_interface::aidl::com::android::compos::ICompOsService::ICompOsService;
+use compos_common::odrefresh::ExitCode;
use log::{error, warn};
+use rustutils::system_properties;
+use std::fs::{File, OpenOptions};
+use std::os::unix::fs::OpenOptionsExt;
+use std::os::unix::io::AsRawFd;
+use std::path::Path;
use std::sync::{Arc, Mutex};
use std::thread;
+const ART_APEX_DATA: &str = "/data/misc/apexdata/com.android.art";
+
#[derive(Clone)]
pub struct OdrefreshTask {
running_task: Arc<Mutex<Option<RunningTask>>>,
@@ -42,6 +52,12 @@
}
}
+struct RunningTask {
+ callback: Strong<dyn ICompilationTaskCallback>,
+ #[allow(dead_code)] // Keeps the CompOS VM alive
+ comp_os: Arc<CompOsInstance>,
+}
+
impl OdrefreshTask {
/// Return the current running task, if any, removing it from this CompilationTask.
/// Once removed, meaning the task has ended or been canceled, further calls will always return
@@ -66,13 +82,13 @@
fn start_thread(self, service: Strong<dyn ICompOsService>, target_dir_name: String) {
thread::spawn(move || {
- let exit_code = odrefresh::run_in_vm(service, &target_dir_name);
+ let exit_code = run_in_vm(service, &target_dir_name);
let task = self.take();
// 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()
@@ -90,8 +106,42 @@
}
}
-struct RunningTask {
- callback: Strong<dyn ICompilationTaskCallback>,
- #[allow(dead_code)] // Keeps the CompOS VM alive
- comp_os: Arc<CompOsInstance>,
+fn run_in_vm(service: Strong<dyn ICompOsService>, target_dir_name: &str) -> Result<ExitCode> {
+ let staging_dir = open_dir(composd_native::palette_create_odrefresh_staging_directory()?)?;
+ let system_dir = open_dir(Path::new("/system"))?;
+ let output_dir = open_dir(Path::new(ART_APEX_DATA))?;
+
+ // Spawn a fd_server to serve the FDs.
+ let fd_server_config = FdServerConfig {
+ ro_dir_fds: vec![system_dir.as_raw_fd()],
+ rw_dir_fds: vec![staging_dir.as_raw_fd(), output_dir.as_raw_fd()],
+ ..Default::default()
+ };
+ let fd_server_raii = fd_server_config.into_fd_server()?;
+
+ let zygote_arch = system_properties::read("ro.zygote")?;
+ let exit_code = service.odrefresh(
+ system_dir.as_raw_fd(),
+ output_dir.as_raw_fd(),
+ staging_dir.as_raw_fd(),
+ target_dir_name,
+ &zygote_arch,
+ )?;
+
+ drop(fd_server_raii);
+ if let Some(exit_code) = ExitCode::from_i32(exit_code.into()) {
+ Ok(exit_code)
+ } else {
+ bail!("odrefresh exited with {}", exit_code)
+ }
+}
+
+/// Returns an owned FD of the directory. It currently returns a `File` as a FD owner, but
+/// it's better to use `std::os::unix::io::OwnedFd` once/if it becomes standard.
+fn open_dir(path: &Path) -> Result<File> {
+ OpenOptions::new()
+ .custom_flags(libc::O_DIRECTORY)
+ .read(true) // O_DIRECTORY can only be opened with read
+ .open(path)
+ .with_context(|| format!("Failed to open {:?} directory as path fd", path))
}
diff --git a/compos/composd/src/service.rs b/compos/composd/src/service.rs
index 6ce462c..23c411b 100644
--- a/compos/composd/src/service.rs
+++ b/compos/composd/src/service.rs
@@ -19,7 +19,6 @@
use crate::compilation_task::CompilationTask;
use crate::instance_manager::InstanceManager;
-use crate::odrefresh;
use crate::odrefresh_task::OdrefreshTask;
use crate::util::to_binder_result;
use android_system_composd::aidl::android::system::composd::{
@@ -71,11 +70,6 @@
check_permissions()?;
to_binder_result(self.do_start_async_odrefresh(callback))
}
-
- fn startTestOdrefresh(&self) -> binder::Result<i8> {
- check_permissions()?;
- to_binder_result(self.do_odrefresh_for_test())
- }
}
impl IsolatedCompilationService {
@@ -113,17 +107,6 @@
Ok(BnCompilationTask::new_binder(task, BinderFeatures::default()))
}
-
- fn do_odrefresh_for_test(&self) -> Result<i8> {
- let compos = self
- .instance_manager
- .start_test_instance()
- .context("Starting CompOS for odrefresh test")?;
- let service = compos.get_service();
-
- let exit_code = odrefresh::run_in_vm(service, "test-artifacts")?;
- Ok(exit_code as i8)
- }
}
fn check_permissions() -> binder::Result<()> {
diff --git a/compos/composd_cmd/composd_cmd.rs b/compos/composd_cmd/composd_cmd.rs
index 37d5378..41e2b1a 100644
--- a/compos/composd_cmd/composd_cmd.rs
+++ b/compos/composd_cmd/composd_cmd.rs
@@ -34,9 +34,11 @@
fn main() -> Result<()> {
let app = clap::App::new("composd_cmd").arg(
- clap::Arg::with_name("command").index(1).takes_value(true).required(true).possible_values(
- &["staged-apex-compile", "forced-compile-test", "forced-odrefresh", "async-odrefresh"],
- ),
+ clap::Arg::with_name("command")
+ .index(1)
+ .takes_value(true)
+ .required(true)
+ .possible_values(&["staged-apex-compile", "forced-compile-test", "async-odrefresh"]),
);
let args = app.get_matches();
let command = args.value_of("command").unwrap();
@@ -46,7 +48,6 @@
match command {
"staged-apex-compile" => run_staged_apex_compile()?,
"forced-compile-test" => run_forced_compile_for_test()?,
- "forced-odrefresh" => run_forced_odrefresh_for_test()?,
"async-odrefresh" => run_async_odrefresh_for_test()?,
_ => panic!("Unexpected command {}", command),
}
@@ -155,11 +156,3 @@
}
}
}
-
-fn run_forced_odrefresh_for_test() -> Result<()> {
- let service = wait_for_interface::<dyn IIsolatedCompilationService>("android.system.composd")
- .context("Failed to connect to composd service")?;
- let compilation_result = service.startTestOdrefresh().context("Compilation failed")?;
- println!("odrefresh exit code: {:?}", compilation_result);
- Ok(())
-}
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()))
}
}
diff --git a/microdroid/build.prop b/microdroid/build.prop
index ada945d..4ae50c0 100644
--- a/microdroid/build.prop
+++ b/microdroid/build.prop
@@ -6,3 +6,6 @@
# TODO(b/189164487): support build related properties
ro.build.version.release=11
ro.build.version.security_patch=2021-07-05
+
+# Payload metadata partition
+apexd.payload_metadata.path=/dev/block/by-name/payload-metadata