Merge "Fix minor compos_key_cmd problems"
diff --git a/apkdmverity/Android.bp b/apkdmverity/Android.bp
index e6b1ca9..403e726 100644
--- a/apkdmverity/Android.bp
+++ b/apkdmverity/Android.bp
@@ -14,6 +14,7 @@
"libclap",
"libdata_model",
"libidsig",
+ "libitertools",
"liblibc",
"libnix",
"libnum_traits",
@@ -32,7 +33,6 @@
rust_binary {
name: "apkdmverity",
defaults: ["apkdmverity.defaults"],
- init_rc: ["apkdmverity.rc"],
bootstrap: true,
}
diff --git a/apkdmverity/apkdmverity.rc b/apkdmverity/apkdmverity.rc
deleted file mode 100644
index c6ef52b..0000000
--- a/apkdmverity/apkdmverity.rc
+++ /dev/null
@@ -1,3 +0,0 @@
-service apkdmverity /system/bin/apkdmverity /dev/block/by-name/microdroid-apk /dev/block/by-name/microdroid-apk-idsig microdroid-apk
- disabled
- oneshot
diff --git a/apkdmverity/src/main.rs b/apkdmverity/src/main.rs
index b240c85..a8a8f15 100644
--- a/apkdmverity/src/main.rs
+++ b/apkdmverity/src/main.rs
@@ -28,6 +28,7 @@
use anyhow::{bail, Context, Result};
use clap::{App, Arg};
use idsig::{HashAlgorithm, V4Signature};
+use itertools::Itertools;
use rustutils::system_properties;
use std::fmt::Debug;
use std::fs;
@@ -38,42 +39,35 @@
fn main() -> Result<()> {
let matches = App::new("apkdmverity")
.about("Creates a dm-verity block device out of APK signed with APK signature scheme V4.")
- .arg(
- Arg::with_name("apk")
- .help("Input APK file. Must be signed using the APK signature scheme V4.")
- .required(true),
- )
- .arg(
- Arg::with_name("idsig")
- .help("The idsig file having the merkle tree and the signing info.")
- .required(true),
- )
- .arg(
- Arg::with_name("name")
- .help(
- "Name of the dm-verity block device. The block device is created at \
- \"/dev/mapper/<name>\".",
- )
- .required(true),
- )
+ .arg(Arg::from_usage(
+ "--apk... <apk_path> <idsig_path> <name> \
+ 'Input APK file, idsig file, and the name of the block device. The APK \
+ file must be signed using the APK signature scheme 4. The block device \
+ is created at \"/dev/mapper/<name>\".'",
+ ))
.arg(Arg::with_name("verbose").short("v").long("verbose").help("Shows verbose output"))
.get_matches();
- let apk = matches.value_of("apk").unwrap();
- let idsig = matches.value_of("idsig").unwrap();
- let name = matches.value_of("name").unwrap();
+ let apks = matches.values_of("apk").unwrap();
+ assert!(apks.len() % 3 == 0);
+
let roothash = if let Ok(val) = system_properties::read("microdroid_manager.apk_root_hash") {
Some(util::parse_hexstring(&val)?)
} else {
// This failure is not an error. We will use the roothash read from the idsig file.
None
};
- let ret = enable_verity(apk, idsig, name, roothash.as_deref())?;
- if matches.is_present("verbose") {
- println!(
- "data_device: {:?}, hash_device: {:?}, mapper_device: {:?}",
- ret.data_device, ret.hash_device, ret.mapper_device
- );
+
+ let verbose = matches.is_present("verbose");
+
+ for (apk, idsig, name) in apks.tuples() {
+ let ret = enable_verity(apk, idsig, name, roothash.as_deref())?;
+ if verbose {
+ println!(
+ "data_device: {:?}, hash_device: {:?}, mapper_device: {:?}",
+ ret.data_device, ret.hash_device, ret.mapper_device
+ );
+ }
}
Ok(())
}
diff --git a/compos/composd/aidl/android/system/composd/IIsolatedCompilationService.aidl b/compos/composd/aidl/android/system/composd/IIsolatedCompilationService.aidl
index 6f4476c..5e72cd2 100644
--- a/compos/composd/aidl/android/system/composd/IIsolatedCompilationService.aidl
+++ b/compos/composd/aidl/android/system/composd/IIsolatedCompilationService.aidl
@@ -20,6 +20,17 @@
interface IIsolatedCompilationService {
/**
+ * Compile BCP extensions and system server, using any staged APEXes that are present in
+ * preference to active APEXes, writing the results to the pending artifacts directory to be
+ * verified by odsing on next boot.
+ *
+ * Compilation continues in the background, and success/failure is reported via the supplied
+ * callback, unless the returned ICompilationTask is cancelled. The caller should maintain
+ * a reference to the ICompilationTask until compilation completes or is cancelled.
+ */
+ ICompilationTask startStagedApexCompile(ICompilationTaskCallback callback);
+
+ /**
* Run "odrefresh --dalvik-cache=pending-test --force-compile" in a test instance of CompOS.
*
* This compiles BCP extensions and system server, even if the system artifacts are up to date,
diff --git a/compos/composd/src/compilation_task.rs b/compos/composd/src/compilation_task.rs
index c4eed52..18f5aac 100644
--- a/compos/composd/src/compilation_task.rs
+++ b/compos/composd/src/compilation_task.rs
@@ -52,6 +52,23 @@
self.running_task.lock().unwrap().take()
}
+ pub fn start_staged_apex_compile(
+ comp_os: Arc<CompOsInstance>,
+ callback: &Strong<dyn ICompilationTaskCallback>,
+ ) -> Result<CompilationTask> {
+ // TODO: Write to pending
+ // TODO: Delete any existing artifacts
+ let odrefresh = Odrefresh::spawn_compile("test-artifacts")?;
+ let odrefresh = Arc::new(odrefresh);
+ let task =
+ RunningTask { odrefresh: odrefresh.clone(), comp_os, callback: callback.clone() };
+ let task = CompilationTask { running_task: Arc::new(Mutex::new(Some(task))) };
+
+ task.clone().start_waiting_thread(odrefresh);
+
+ Ok(task)
+ }
+
pub fn start_test_compile(
comp_os: Arc<CompOsInstance>,
callback: &Strong<dyn ICompilationTaskCallback>,
diff --git a/compos/composd/src/instance_manager.rs b/compos/composd/src/instance_manager.rs
index 6291d59..767e9f7 100644
--- a/compos/composd/src/instance_manager.rs
+++ b/compos/composd/src/instance_manager.rs
@@ -23,7 +23,7 @@
use compos_aidl_interface::aidl::com::android::compos::ICompOsService::ICompOsService;
use compos_aidl_interface::binder::Strong;
use compos_common::compos_client::VmParameters;
-use compos_common::{CURRENT_INSTANCE_DIR, TEST_INSTANCE_DIR};
+use compos_common::{PENDING_INSTANCE_DIR, TEST_INSTANCE_DIR};
use std::sync::{Arc, Mutex, Weak};
use virtualizationservice::IVirtualizationService::IVirtualizationService;
@@ -43,9 +43,8 @@
Ok(instance.get_service())
}
- #[allow(dead_code)] // TODO: Make use of this
- pub fn start_current_instance(&self) -> Result<Arc<CompOsInstance>> {
- self.start_instance(CURRENT_INSTANCE_DIR, VmParameters::default())
+ pub fn start_pending_instance(&self) -> Result<Arc<CompOsInstance>> {
+ self.start_instance(PENDING_INSTANCE_DIR, VmParameters::default())
}
pub fn start_test_instance(&self) -> Result<Arc<CompOsInstance>> {
diff --git a/compos/composd/src/instance_starter.rs b/compos/composd/src/instance_starter.rs
index 3e18c3e..8189fe0 100644
--- a/compos/composd/src/instance_starter.rs
+++ b/compos/composd/src/instance_starter.rs
@@ -199,7 +199,7 @@
fn check_files_exist(&self) -> Result<()> {
if !self.instance_root.is_dir() {
- bail!("Directory {} not found", self.instance_root.display())
+ bail!("Directory {:?} not found", self.instance_root)
};
Self::check_file_exists(&self.instance_image)?;
Self::check_file_exists(&self.key_blob)?;
@@ -209,7 +209,7 @@
fn check_file_exists(file: &Path) -> Result<()> {
if !file.is_file() {
- bail!("File {} not found", file.display())
+ bail!("File {:?} not found", file)
};
Ok(())
}
diff --git a/compos/composd/src/odrefresh.rs b/compos/composd/src/odrefresh.rs
index 16dcb0f..9debf00 100644
--- a/compos/composd/src/odrefresh.rs
+++ b/compos/composd/src/odrefresh.rs
@@ -44,7 +44,15 @@
}
impl Odrefresh {
+ pub fn spawn_compile(target_dir: &str) -> Result<Self> {
+ Self::spawn_odrefresh(target_dir, "--compile")
+ }
+
pub fn spawn_forced_compile(target_dir: &str) -> Result<Self> {
+ Self::spawn_odrefresh(target_dir, "--force-compile")
+ }
+
+ 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);
if need_extra_time()? {
@@ -61,7 +69,7 @@
cmdline
.arg(format!("--use-compilation-os={}", VMADDR_CID_ANY as i32))
.arg(format!("--dalvik-cache={}", target_dir))
- .arg("--force-compile");
+ .arg(compile_arg);
let child = SharedChild::spawn(&mut cmdline).context("Running odrefresh")?;
Ok(Odrefresh { child })
}
diff --git a/compos/composd/src/service.rs b/compos/composd/src/service.rs
index 3738e18..aa96ddf 100644
--- a/compos/composd/src/service.rs
+++ b/compos/composd/src/service.rs
@@ -53,21 +53,41 @@
impl Interface for IsolatedCompilationService {}
impl IIsolatedCompilationService for IsolatedCompilationService {
+ fn startStagedApexCompile(
+ &self,
+ callback: &Strong<dyn ICompilationTaskCallback>,
+ ) -> binder::Result<Strong<dyn ICompilationTask>> {
+ check_permissions()?;
+ to_binder_result(self.do_start_staged_apex_compile(callback))
+ }
+
fn startTestCompile(
&self,
callback: &Strong<dyn ICompilationTaskCallback>,
) -> binder::Result<Strong<dyn ICompilationTask>> {
- check_test_permissions()?;
+ check_permissions()?;
to_binder_result(self.do_start_test_compile(callback))
}
fn startTestOdrefresh(&self) -> binder::Result<i8> {
- check_test_permissions()?;
+ check_permissions()?;
to_binder_result(self.do_odrefresh_for_test())
}
}
impl IsolatedCompilationService {
+ fn do_start_staged_apex_compile(
+ &self,
+ callback: &Strong<dyn ICompilationTaskCallback>,
+ ) -> Result<Strong<dyn ICompilationTask>> {
+ // TODO: Try to start the current instance with staged APEXes to see if it works?
+ let comp_os = self.instance_manager.start_pending_instance().context("Starting CompOS")?;
+
+ let task = CompilationTask::start_staged_apex_compile(comp_os, callback)?;
+
+ Ok(BnCompilationTask::new_binder(task, BinderFeatures::default()))
+ }
+
fn do_start_test_compile(
&self,
callback: &Strong<dyn ICompilationTaskCallback>,
@@ -114,7 +134,7 @@
}
}
-fn check_test_permissions() -> binder::Result<()> {
+fn check_permissions() -> binder::Result<()> {
let calling_uid = ThreadState::get_calling_uid();
// This should only be called by system server, or root while testing
if calling_uid != AID_SYSTEM && calling_uid != AID_ROOT {
@@ -135,5 +155,5 @@
// make the library happy. The value does not appear to matter elsewhere in the library.
.read(true)
.open(path)
- .with_context(|| format!("Failed to open {} directory as path fd", path.display()))
+ .with_context(|| format!("Failed to open {:?} directory as path fd", path))
}
diff --git a/compos/composd_cmd/composd_cmd.rs b/compos/composd_cmd/composd_cmd.rs
index e591794..f22dc13 100644
--- a/compos/composd_cmd/composd_cmd.rs
+++ b/compos/composd_cmd/composd_cmd.rs
@@ -18,12 +18,13 @@
use android_system_composd::{
aidl::android::system::composd::{
+ ICompilationTask::ICompilationTask,
ICompilationTaskCallback::{BnCompilationTaskCallback, ICompilationTaskCallback},
IIsolatedCompilationService::IIsolatedCompilationService,
},
binder::{
wait_for_interface, BinderFeatures, DeathRecipient, IBinder, Interface, ProcessState,
- Result as BinderResult,
+ Result as BinderResult, Strong,
},
};
use anyhow::{bail, Context, Result};
@@ -37,7 +38,7 @@
.index(1)
.takes_value(true)
.required(true)
- .possible_values(&["forced-compile-test", "forced-odrefresh"]),
+ .possible_values(&["staged-apex-compile", "forced-compile-test", "forced-odrefresh"]),
);
let args = app.get_matches();
let command = args.value_of("command").unwrap();
@@ -45,6 +46,7 @@
ProcessState::start_thread_pool();
match command {
+ "staged-apex-compile" => run_staged_apex_compile()?,
"forced-compile-test" => run_forced_compile_for_test()?,
"forced-odrefresh" => run_forced_odrefresh_for_test()?,
_ => panic!("Unexpected command {}", command),
@@ -103,14 +105,28 @@
}
}
+fn run_staged_apex_compile() -> Result<()> {
+ run_async_compilation(|service, callback| service.startStagedApexCompile(callback))
+}
+
fn run_forced_compile_for_test() -> Result<()> {
+ run_async_compilation(|service, callback| service.startTestCompile(callback))
+}
+
+fn run_async_compilation<F>(start_compile_fn: F) -> Result<()>
+where
+ F: FnOnce(
+ &dyn IIsolatedCompilationService,
+ &Strong<dyn ICompilationTaskCallback>,
+ ) -> BinderResult<Strong<dyn ICompilationTask>>,
+{
let service = wait_for_interface::<dyn IIsolatedCompilationService>("android.system.composd")
.context("Failed to connect to composd service")?;
let state = Arc::new(State::default());
let callback = Callback(state.clone());
let callback = BnCompilationTaskCallback::new_binder(callback, BinderFeatures::default());
- let task = service.startTestCompile(&callback).context("Compilation failed")?;
+ let task = start_compile_fn(&*service, &callback).context("Compilation failed")?;
// Make sure composd keeps going even if we don't hold a reference to its service.
drop(service);
diff --git a/compos/service/java/com/android/server/compos/IsolatedCompilationJobService.java b/compos/service/java/com/android/server/compos/IsolatedCompilationJobService.java
index da399cc..685d60c 100644
--- a/compos/service/java/com/android/server/compos/IsolatedCompilationJobService.java
+++ b/compos/service/java/com/android/server/compos/IsolatedCompilationJobService.java
@@ -138,6 +138,7 @@
}
try {
+ // TODO(b/205296305) Call startStagedApexCompile instead
ICompilationTask composTask = composd.startTestCompile(this);
mTask.set(composTask);
composTask.asBinder().linkToDeath(this, 0);
diff --git a/compos/src/compilation.rs b/compos/src/compilation.rs
index b726a1e..44b4049 100644
--- a/compos/src/compilation.rs
+++ b/compos/src/compilation.rs
@@ -86,14 +86,20 @@
android_root.push("system");
env::set_var("ANDROID_ROOT", &android_root);
+ let mut art_apex_data = mountpoint.clone();
+ art_apex_data.push(output_dir_fd.to_string());
+ env::set_var("ART_APEX_DATA", &art_apex_data);
+
let mut staging_dir = mountpoint;
staging_dir.push(output_dir_fd.to_string());
staging_dir.push("staging");
- create_dir(&staging_dir).context("Create staging directory")?;
+ create_dir(&staging_dir)
+ .with_context(|| format!("Create staging directory {}", staging_dir.display()))?;
let args = vec![
"odrefresh".to_string(),
format!("--zygote-arch={}", zygote_arch),
+ "--no-refresh".to_string(),
format!("--staging-dir={}", staging_dir.display()),
"--force-compile".to_string(),
];
@@ -103,7 +109,7 @@
// TODO(161471326): On success, sign all files in the output directory.
Ok(()) => Ok(CompilerOutput::ExitCode(0)),
Err(minijail::Error::ReturnCode(exit_code)) => {
- error!("dex2oat failed with exit code {}", exit_code);
+ error!("odrefresh failed with exit code {}", exit_code);
Ok(CompilerOutput::ExitCode(exit_code as i8))
}
Err(e) => {
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 2e6fa36..99ebc51 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -33,7 +33,7 @@
use std::fs::{self, File, OpenOptions};
use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::path::Path;
-use std::process::{Command, Stdio};
+use std::process::{Child, Command, Stdio};
use std::str;
use std::time::{Duration, SystemTime};
use vsock::VsockStream;
@@ -43,7 +43,16 @@
};
const WAIT_TIMEOUT: Duration = Duration::from_secs(10);
+const APK_DM_VERITY_ARGUMENT: ApkDmverityArgument = {
+ ApkDmverityArgument {
+ apk: "/dev/block/by-name/microdroid-apk",
+ idsig: "/dev/block/by-name/microdroid-apk-idsig",
+ name: "microdroid-apk",
+ }
+};
const DM_MOUNTED_APK_PATH: &str = "/dev/block/mapper/microdroid-apk";
+const APKDMVERITY_BIN: &str = "/system/bin/apkdmverity";
+const ZIPFUSE_BIN: &str = "/system/bin/zipfuse";
/// The CID representing the host VM
const VMADDR_CID_HOST: u32 = 2;
@@ -135,7 +144,12 @@
}
// Before reading a file from the APK, start zipfuse
- system_properties::write("ctl.start", "zipfuse")?;
+ run_zipfuse(
+ "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0",
+ Path::new("/dev/block/mapper/microdroid-apk"),
+ Path::new("/mnt/apk"),
+ )
+ .context("Failed to run zipfuse")?;
if !metadata.payload_config_path.is_empty() {
let config = load_config(Path::new(&metadata.payload_config_path))?;
@@ -160,6 +174,37 @@
Ok(())
}
+struct ApkDmverityArgument<'a> {
+ apk: &'a str,
+ idsig: &'a str,
+ name: &'a str,
+}
+
+fn run_apkdmverity(args: &[ApkDmverityArgument]) -> Result<Child> {
+ let mut cmd = Command::new(APKDMVERITY_BIN);
+
+ cmd.stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
+
+ for argument in args {
+ cmd.arg("--apk").arg(argument.apk).arg(argument.idsig).arg(argument.name);
+ }
+
+ cmd.spawn().context("Spawn apkdmverity")
+}
+
+fn run_zipfuse(option: &str, zip_path: &Path, mount_dir: &Path) -> Result<Child> {
+ Command::new(ZIPFUSE_BIN)
+ .arg("-o")
+ .arg(option)
+ .arg(zip_path)
+ .arg(mount_dir)
+ .stdin(Stdio::null())
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .spawn()
+ .context("Spawn zipfuse")
+}
+
// Verify payload before executing it. For APK payload, Full verification (which is slow) is done
// when the root_hash values from the idsig file and the instance disk are different. This function
// returns the verified root hash (for APK payload) and pubkeys (for APEX payloads) that can be
@@ -182,7 +227,7 @@
}
// Start apkdmverity and wait for the dm-verify block
- system_properties::write("ctl.start", "apkdmverity")?;
+ let mut apkdmverity_child = run_apkdmverity(&[APK_DM_VERITY_ARGUMENT])?;
// While waiting for apkdmverity to mount APK, gathers public keys and root digests from
// APEX payload.
@@ -206,7 +251,8 @@
// Start apexd to activate APEXes
system_properties::write("ctl.start", "apexd-vm")?;
- ioutil::wait_for_file(DM_MOUNTED_APK_PATH, WAIT_TIMEOUT)?;
+ // TODO(inseob): add timeout
+ apkdmverity_child.wait()?;
// Do the full verification if the root_hash is un-trustful. This requires the full scanning of
// the APK file and therefore can be very slow if the APK is large. Note that this step is
diff --git a/zipfuse/Android.bp b/zipfuse/Android.bp
index 79e6bad..e10fc31 100644
--- a/zipfuse/Android.bp
+++ b/zipfuse/Android.bp
@@ -28,7 +28,6 @@
rust_binary {
name: "zipfuse",
defaults: ["zipfuse.defaults"],
- init_rc: ["zipfuse.rc"],
bootstrap: true,
}
diff --git a/zipfuse/zipfuse.rc b/zipfuse/zipfuse.rc
deleted file mode 100644
index 1905705..0000000
--- a/zipfuse/zipfuse.rc
+++ /dev/null
@@ -1,2 +0,0 @@
-service zipfuse /system/bin/zipfuse -o fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0 /dev/block/mapper/microdroid-apk /mnt/apk
- disabled