Use --force-compile for tests

The test uses --force-compile outside the VM, so we also need to
inside the VM. But we want --compile for the normal case of
compilation, so we only produce exactly the required artifacts.

That means we have to pass whether we are testing or not from the host
to guest, so lots of plumbing is needed.

(Also figured out how to solve a problem with type deduction that the
me of a few months ago was baffled by.)

Bug: 211458160
Test: atest ComposTestCase
Change-Id: Ie7e36bc3fab40744e9f9ea5e5928126899d9060d
This commit is contained in:
Alan Stokes 2022-01-28 16:41:52 +00:00
parent 4382754aa8
commit 2d2e4dba53
6 changed files with 72 additions and 17 deletions

View File

@ -28,6 +28,7 @@ rust_defaults {
"libprotobuf", "libprotobuf",
"libregex", "libregex",
"libring", "libring",
"librustutils",
"libscopeguard", "libscopeguard",
], ],
prefer_rlib: true, prefer_rlib: true,

View File

@ -20,6 +20,17 @@ import com.android.compos.CompOsKeyData;
/** {@hide} */ /** {@hide} */
interface ICompOsService { interface ICompOsService {
/**
* What type of compilation to perform.
*/
@Backing(type="int")
enum CompilationMode {
/** Compile artifacts required by the current set of APEXes for use on reboot. */
NORMAL_COMPILE = 0,
/** Compile a full set of artifacts for test purposes. */
TEST_COMPILE = 1,
}
/** /**
* Initializes the service with the supplied encrypted private key blob. The key cannot be * Initializes the service with the supplied encrypted private key blob. The key cannot be
* changed once initialized, so once initiailzed, a repeated call will fail with * changed once initialized, so once initiailzed, a repeated call will fail with
@ -37,6 +48,7 @@ interface ICompOsService {
* through systemDirFd over AuthFS), and *CLASSPATH derived in the VM, to generate the same * through systemDirFd over AuthFS), and *CLASSPATH derived in the VM, to generate the same
* odrefresh output artifacts to the output directory (through outputDirFd). * odrefresh output artifacts to the output directory (through outputDirFd).
* *
* @param compilationMode The type of compilation to be performed
* @param systemDirFd An fd referring to /system * @param systemDirFd An fd referring to /system
* @param outputDirFd An fd referring to the output directory, ART_APEX_DATA * @param outputDirFd An fd referring to the output directory, ART_APEX_DATA
* @param stagingDirFd An fd referring to the staging directory, e.g. ART_APEX_DATA/staging * @param stagingDirFd An fd referring to the staging directory, e.g. ART_APEX_DATA/staging
@ -46,8 +58,9 @@ interface ICompOsService {
* @param systemServerCompilerFilter The compiler filter used to compile system server * @param systemServerCompilerFilter The compiler filter used to compile system server
* @return odrefresh exit code * @return odrefresh exit code
*/ */
byte odrefresh(int systemDirFd, int outputDirFd, int stagingDirFd, String targetDirName, byte odrefresh(CompilationMode compilation_mode, int systemDirFd, int outputDirFd,
String zygoteArch, String systemServerCompilerFilter); int stagingDirFd, String targetDirName, String zygoteArch,
String systemServerCompilerFilter);
/** /**
* Generate a new public/private key pair suitable for signing CompOs output files. * Generate a new public/private key pair suitable for signing CompOs output files.

View File

@ -23,7 +23,9 @@ use android_system_composd::aidl::android::system::composd::{
}; };
use android_system_composd::binder::{Interface, Result as BinderResult, Strong}; use android_system_composd::binder::{Interface, Result as BinderResult, Strong};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use compos_aidl_interface::aidl::com::android::compos::ICompOsService::ICompOsService; use compos_aidl_interface::aidl::com::android::compos::ICompOsService::{
CompilationMode::CompilationMode, ICompOsService,
};
use compos_common::odrefresh::ExitCode; use compos_common::odrefresh::ExitCode;
use log::{error, warn}; use log::{error, warn};
use rustutils::system_properties; use rustutils::system_properties;
@ -68,6 +70,7 @@ impl OdrefreshTask {
pub fn start( pub fn start(
comp_os: Arc<CompOsInstance>, comp_os: Arc<CompOsInstance>,
compilation_mode: CompilationMode,
target_dir_name: String, target_dir_name: String,
callback: &Strong<dyn ICompilationTaskCallback>, callback: &Strong<dyn ICompilationTaskCallback>,
) -> Result<OdrefreshTask> { ) -> Result<OdrefreshTask> {
@ -75,14 +78,19 @@ impl OdrefreshTask {
let task = RunningTask { comp_os, callback: callback.clone() }; let task = RunningTask { comp_os, callback: callback.clone() };
let task = OdrefreshTask { running_task: Arc::new(Mutex::new(Some(task))) }; let task = OdrefreshTask { running_task: Arc::new(Mutex::new(Some(task))) };
task.clone().start_thread(service, target_dir_name); task.clone().start_thread(service, compilation_mode, target_dir_name);
Ok(task) Ok(task)
} }
fn start_thread(self, service: Strong<dyn ICompOsService>, target_dir_name: String) { fn start_thread(
self,
service: Strong<dyn ICompOsService>,
compilation_mode: CompilationMode,
target_dir_name: String,
) {
thread::spawn(move || { thread::spawn(move || {
let exit_code = run_in_vm(service, &target_dir_name); let exit_code = run_in_vm(service, compilation_mode, &target_dir_name);
let task = self.take(); let task = self.take();
// We don't do the callback if cancel has already happened. // We don't do the callback if cancel has already happened.
@ -106,7 +114,11 @@ impl OdrefreshTask {
} }
} }
fn run_in_vm(service: Strong<dyn ICompOsService>, target_dir_name: &str) -> Result<ExitCode> { fn run_in_vm(
service: Strong<dyn ICompOsService>,
compilation_mode: CompilationMode,
target_dir_name: &str,
) -> Result<ExitCode> {
let output_root = Path::new(ART_APEX_DATA); let output_root = Path::new(ART_APEX_DATA);
// We need to remove the target directory because odrefresh running in compos will create it // We need to remove the target directory because odrefresh running in compos will create it
@ -134,6 +146,7 @@ fn run_in_vm(service: Strong<dyn ICompOsService>, target_dir_name: &str) -> Resu
let system_server_compiler_filter = let system_server_compiler_filter =
system_properties::read("dalvik.vm.systemservercompilerfilter").unwrap_or_default(); system_properties::read("dalvik.vm.systemservercompilerfilter").unwrap_or_default();
let exit_code = service.odrefresh( let exit_code = service.odrefresh(
compilation_mode,
system_dir.as_raw_fd(), system_dir.as_raw_fd(),
output_dir.as_raw_fd(), output_dir.as_raw_fd(),
staging_dir.as_raw_fd(), staging_dir.as_raw_fd(),

View File

@ -28,6 +28,7 @@ use android_system_composd::binder::{
self, BinderFeatures, ExceptionCode, Interface, Status, Strong, ThreadState, self, BinderFeatures, ExceptionCode, Interface, Status, Strong, ThreadState,
}; };
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use compos_aidl_interface::aidl::com::android::compos::ICompOsService::CompilationMode::CompilationMode;
use compos_common::binder::to_binder_result; use compos_common::binder::to_binder_result;
use rustutils::{users::AID_ROOT, users::AID_SYSTEM}; use rustutils::{users::AID_ROOT, users::AID_SYSTEM};
use std::sync::Arc; use std::sync::Arc;
@ -72,7 +73,12 @@ impl IsolatedCompilationService {
let comp_os = self.instance_manager.start_pending_instance().context("Starting CompOS")?; let comp_os = self.instance_manager.start_pending_instance().context("Starting CompOS")?;
let target_dir_name = "compos-pending".to_owned(); let target_dir_name = "compos-pending".to_owned();
let task = OdrefreshTask::start(comp_os, target_dir_name, callback)?; let task = OdrefreshTask::start(
comp_os,
CompilationMode::NORMAL_COMPILE,
target_dir_name,
callback,
)?;
Ok(BnCompilationTask::new_binder(task, BinderFeatures::default())) Ok(BnCompilationTask::new_binder(task, BinderFeatures::default()))
} }
@ -84,7 +90,12 @@ impl IsolatedCompilationService {
let comp_os = self.instance_manager.start_test_instance().context("Starting CompOS")?; let comp_os = self.instance_manager.start_test_instance().context("Starting CompOS")?;
let target_dir_name = "test-artifacts".to_owned(); let target_dir_name = "test-artifacts".to_owned();
let task = OdrefreshTask::start(comp_os, target_dir_name, callback)?; let task = OdrefreshTask::start(
comp_os,
CompilationMode::TEST_COMPILE,
target_dir_name,
callback,
)?;
Ok(BnCompilationTask::new_binder(task, BinderFeatures::default())) Ok(BnCompilationTask::new_binder(task, BinderFeatures::default()))
} }

View File

@ -18,6 +18,7 @@ use anyhow::{anyhow, bail, Context, Result};
use log::{debug, info, warn}; use log::{debug, info, warn};
use minijail::{self, Minijail}; use minijail::{self, Minijail};
use regex::Regex; use regex::Regex;
use rustutils::system_properties;
use std::collections::HashMap; use std::collections::HashMap;
use std::env; use std::env;
use std::ffi::OsString; use std::ffi::OsString;
@ -35,11 +36,13 @@ use authfs_aidl_interface::aidl::com::android::virt::fs::{
IAuthFsService::IAuthFsService, IAuthFsService::IAuthFsService,
}; };
use authfs_aidl_interface::binder::Strong; use authfs_aidl_interface::binder::Strong;
use compos_aidl_interface::aidl::com::android::compos::ICompOsService::CompilationMode::CompilationMode;
use compos_common::odrefresh::ExitCode; use compos_common::odrefresh::ExitCode;
const FD_SERVER_PORT: i32 = 3264; // TODO: support dynamic port const FD_SERVER_PORT: i32 = 3264; // TODO: support dynamic port
pub struct OdrefreshContext<'a> { pub struct OdrefreshContext<'a> {
compilation_mode: CompilationMode,
system_dir_fd: i32, system_dir_fd: i32,
output_dir_fd: i32, output_dir_fd: i32,
staging_dir_fd: i32, staging_dir_fd: i32,
@ -50,6 +53,7 @@ pub struct OdrefreshContext<'a> {
impl<'a> OdrefreshContext<'a> { impl<'a> OdrefreshContext<'a> {
pub fn new( pub fn new(
compilation_mode: CompilationMode,
system_dir_fd: i32, system_dir_fd: i32,
output_dir_fd: i32, output_dir_fd: i32,
staging_dir_fd: i32, staging_dir_fd: i32,
@ -57,6 +61,13 @@ impl<'a> OdrefreshContext<'a> {
zygote_arch: &'a str, zygote_arch: &'a str,
system_server_compiler_filter: &'a str, system_server_compiler_filter: &'a str,
) -> Result<Self> { ) -> Result<Self> {
if compilation_mode != CompilationMode::NORMAL_COMPILE {
let debuggable = system_properties::read_bool("ro.boot.microdroid.debuggable", false)?;
if !debuggable {
bail!("Requested compilation mode only available in debuggable VMs");
}
}
if system_dir_fd < 0 || output_dir_fd < 0 || staging_dir_fd < 0 { if system_dir_fd < 0 || output_dir_fd < 0 || staging_dir_fd < 0 {
bail!("The remote FDs are expected to be non-negative"); bail!("The remote FDs are expected to be non-negative");
} }
@ -75,6 +86,7 @@ impl<'a> OdrefreshContext<'a> {
// CompOS. // CompOS.
Ok(Self { Ok(Self {
compilation_mode,
system_dir_fd, system_dir_fd,
output_dir_fd, output_dir_fd,
staging_dir_fd, staging_dir_fd,
@ -143,18 +155,21 @@ pub fn odrefresh(
)); ));
} }
args.push("--compile".to_string()); let compile_flag = match context.compilation_mode {
CompilationMode::NORMAL_COMPILE => "--compile",
CompilationMode::TEST_COMPILE => "--force-compile",
other => bail!("Unknown compilation mode {:?}", other),
};
args.push(compile_flag.to_string());
debug!("Running odrefresh with args: {:?}", &args); debug!("Running odrefresh with args: {:?}", &args);
let jail = spawn_jailed_task(odrefresh_path, &args, &odrefresh_vars.into_env()) let jail = spawn_jailed_task(odrefresh_path, &args, &odrefresh_vars.into_env())
.context("Spawn odrefresh")?; .context("Spawn odrefresh")?;
let exit_code = match jail.wait() { let exit_code = match jail.wait() {
Ok(_) => Result::<u8>::Ok(0), Ok(_) => 0,
Err(minijail::Error::ReturnCode(exit_code)) => Ok(exit_code), Err(minijail::Error::ReturnCode(exit_code)) => exit_code,
Err(e) => { Err(e) => bail!("Unexpected minijail error: {}", e),
bail!("Unexpected minijail error: {}", e) };
}
}?;
let exit_code = ExitCode::from_i32(exit_code.into())?; let exit_code = ExitCode::from_i32(exit_code.into())?;
info!("odrefresh exited with {:?}", exit_code); info!("odrefresh exited with {:?}", exit_code);

View File

@ -31,7 +31,7 @@ use crate::signing_key::{Signer, SigningKey};
use authfs_aidl_interface::aidl::com::android::virt::fs::IAuthFsService::IAuthFsService; use authfs_aidl_interface::aidl::com::android::virt::fs::IAuthFsService::IAuthFsService;
use compos_aidl_interface::aidl::com::android::compos::{ use compos_aidl_interface::aidl::com::android::compos::{
CompOsKeyData::CompOsKeyData, CompOsKeyData::CompOsKeyData,
ICompOsService::{BnCompOsService, ICompOsService}, ICompOsService::{BnCompOsService, CompilationMode::CompilationMode, ICompOsService},
}; };
use compos_aidl_interface::binder::{ use compos_aidl_interface::binder::{
BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Strong, BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Strong,
@ -82,6 +82,7 @@ impl ICompOsService for CompOsService {
fn odrefresh( fn odrefresh(
&self, &self,
compilation_mode: CompilationMode,
system_dir_fd: i32, system_dir_fd: i32,
output_dir_fd: i32, output_dir_fd: i32,
staging_dir_fd: i32, staging_dir_fd: i32,
@ -90,6 +91,7 @@ impl ICompOsService for CompOsService {
system_server_compiler_filter: &str, system_server_compiler_filter: &str,
) -> BinderResult<i8> { ) -> BinderResult<i8> {
let context = to_binder_result(OdrefreshContext::new( let context = to_binder_result(OdrefreshContext::new(
compilation_mode,
system_dir_fd, system_dir_fd,
output_dir_fd, output_dir_fd,
staging_dir_fd, staging_dir_fd,