From 2d2e4dba53eb425c7f4914234b19aced6f21e057 Mon Sep 17 00:00:00 2001 From: Alan Stokes Date: Fri, 28 Jan 2022 16:41:52 +0000 Subject: [PATCH] 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 --- compos/Android.bp | 1 + .../com/android/compos/ICompOsService.aidl | 17 +++++++++-- compos/composd/src/odrefresh_task.rs | 23 +++++++++++---- compos/composd/src/service.rs | 15 ++++++++-- compos/src/compilation.rs | 29 ++++++++++++++----- compos/src/compsvc.rs | 4 ++- 6 files changed, 72 insertions(+), 17 deletions(-) diff --git a/compos/Android.bp b/compos/Android.bp index c54348af..0bcbcdd0 100644 --- a/compos/Android.bp +++ b/compos/Android.bp @@ -28,6 +28,7 @@ rust_defaults { "libprotobuf", "libregex", "libring", + "librustutils", "libscopeguard", ], prefer_rlib: true, diff --git a/compos/aidl/com/android/compos/ICompOsService.aidl b/compos/aidl/com/android/compos/ICompOsService.aidl index cead5d0c..18e163e6 100644 --- a/compos/aidl/com/android/compos/ICompOsService.aidl +++ b/compos/aidl/com/android/compos/ICompOsService.aidl @@ -20,6 +20,17 @@ import com.android.compos.CompOsKeyData; /** {@hide} */ 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 * 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 * 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 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 @@ -46,8 +58,9 @@ interface ICompOsService { * @param systemServerCompilerFilter The compiler filter used to compile system server * @return odrefresh exit code */ - byte odrefresh(int systemDirFd, int outputDirFd, int stagingDirFd, String targetDirName, - String zygoteArch, String systemServerCompilerFilter); + byte odrefresh(CompilationMode compilation_mode, int systemDirFd, int outputDirFd, + int stagingDirFd, String targetDirName, String zygoteArch, + String systemServerCompilerFilter); /** * Generate a new public/private key pair suitable for signing CompOs output files. diff --git a/compos/composd/src/odrefresh_task.rs b/compos/composd/src/odrefresh_task.rs index 330f0abf..47ff590e 100644 --- a/compos/composd/src/odrefresh_task.rs +++ b/compos/composd/src/odrefresh_task.rs @@ -23,7 +23,9 @@ use android_system_composd::aidl::android::system::composd::{ }; use android_system_composd::binder::{Interface, Result as BinderResult, Strong}; 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 log::{error, warn}; use rustutils::system_properties; @@ -68,6 +70,7 @@ impl OdrefreshTask { pub fn start( comp_os: Arc, + compilation_mode: CompilationMode, target_dir_name: String, callback: &Strong, ) -> Result { @@ -75,14 +78,19 @@ impl OdrefreshTask { let task = RunningTask { comp_os, callback: callback.clone() }; 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) } - fn start_thread(self, service: Strong, target_dir_name: String) { + fn start_thread( + self, + service: Strong, + compilation_mode: CompilationMode, + target_dir_name: String, + ) { 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(); // We don't do the callback if cancel has already happened. @@ -106,7 +114,11 @@ impl OdrefreshTask { } } -fn run_in_vm(service: Strong, target_dir_name: &str) -> Result { +fn run_in_vm( + service: Strong, + compilation_mode: CompilationMode, + target_dir_name: &str, +) -> Result { let output_root = Path::new(ART_APEX_DATA); // 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, target_dir_name: &str) -> Resu let system_server_compiler_filter = system_properties::read("dalvik.vm.systemservercompilerfilter").unwrap_or_default(); let exit_code = service.odrefresh( + compilation_mode, system_dir.as_raw_fd(), output_dir.as_raw_fd(), staging_dir.as_raw_fd(), diff --git a/compos/composd/src/service.rs b/compos/composd/src/service.rs index 6cdcd85d..f4121e76 100644 --- a/compos/composd/src/service.rs +++ b/compos/composd/src/service.rs @@ -28,6 +28,7 @@ use android_system_composd::binder::{ self, BinderFeatures, ExceptionCode, Interface, Status, Strong, ThreadState, }; use anyhow::{Context, Result}; +use compos_aidl_interface::aidl::com::android::compos::ICompOsService::CompilationMode::CompilationMode; use compos_common::binder::to_binder_result; use rustutils::{users::AID_ROOT, users::AID_SYSTEM}; use std::sync::Arc; @@ -72,7 +73,12 @@ impl IsolatedCompilationService { let comp_os = self.instance_manager.start_pending_instance().context("Starting CompOS")?; 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())) } @@ -84,7 +90,12 @@ impl IsolatedCompilationService { let comp_os = self.instance_manager.start_test_instance().context("Starting CompOS")?; 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())) } diff --git a/compos/src/compilation.rs b/compos/src/compilation.rs index e8f55f86..7e3834ab 100644 --- a/compos/src/compilation.rs +++ b/compos/src/compilation.rs @@ -18,6 +18,7 @@ use anyhow::{anyhow, bail, Context, Result}; use log::{debug, info, warn}; use minijail::{self, Minijail}; use regex::Regex; +use rustutils::system_properties; use std::collections::HashMap; use std::env; use std::ffi::OsString; @@ -35,11 +36,13 @@ use authfs_aidl_interface::aidl::com::android::virt::fs::{ IAuthFsService::IAuthFsService, }; use authfs_aidl_interface::binder::Strong; +use compos_aidl_interface::aidl::com::android::compos::ICompOsService::CompilationMode::CompilationMode; use compos_common::odrefresh::ExitCode; const FD_SERVER_PORT: i32 = 3264; // TODO: support dynamic port pub struct OdrefreshContext<'a> { + compilation_mode: CompilationMode, system_dir_fd: i32, output_dir_fd: i32, staging_dir_fd: i32, @@ -50,6 +53,7 @@ pub struct OdrefreshContext<'a> { impl<'a> OdrefreshContext<'a> { pub fn new( + compilation_mode: CompilationMode, system_dir_fd: i32, output_dir_fd: i32, staging_dir_fd: i32, @@ -57,6 +61,13 @@ impl<'a> OdrefreshContext<'a> { zygote_arch: &'a str, system_server_compiler_filter: &'a str, ) -> Result { + 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 { bail!("The remote FDs are expected to be non-negative"); } @@ -75,6 +86,7 @@ impl<'a> OdrefreshContext<'a> { // CompOS. Ok(Self { + compilation_mode, system_dir_fd, output_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); let jail = spawn_jailed_task(odrefresh_path, &args, &odrefresh_vars.into_env()) .context("Spawn odrefresh")?; let exit_code = match jail.wait() { - Ok(_) => Result::::Ok(0), - Err(minijail::Error::ReturnCode(exit_code)) => Ok(exit_code), - Err(e) => { - bail!("Unexpected minijail error: {}", e) - } - }?; + Ok(_) => 0, + Err(minijail::Error::ReturnCode(exit_code)) => exit_code, + Err(e) => bail!("Unexpected minijail error: {}", e), + }; let exit_code = ExitCode::from_i32(exit_code.into())?; info!("odrefresh exited with {:?}", exit_code); diff --git a/compos/src/compsvc.rs b/compos/src/compsvc.rs index 422f2712..9d754a79 100644 --- a/compos/src/compsvc.rs +++ b/compos/src/compsvc.rs @@ -31,7 +31,7 @@ use crate::signing_key::{Signer, SigningKey}; use authfs_aidl_interface::aidl::com::android::virt::fs::IAuthFsService::IAuthFsService; use compos_aidl_interface::aidl::com::android::compos::{ CompOsKeyData::CompOsKeyData, - ICompOsService::{BnCompOsService, ICompOsService}, + ICompOsService::{BnCompOsService, CompilationMode::CompilationMode, ICompOsService}, }; use compos_aidl_interface::binder::{ BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Strong, @@ -82,6 +82,7 @@ impl ICompOsService for CompOsService { fn odrefresh( &self, + compilation_mode: CompilationMode, system_dir_fd: i32, output_dir_fd: i32, staging_dir_fd: i32, @@ -90,6 +91,7 @@ impl ICompOsService for CompOsService { system_server_compiler_filter: &str, ) -> BinderResult { let context = to_binder_result(OdrefreshContext::new( + compilation_mode, system_dir_fd, output_dir_fd, staging_dir_fd,