Merge "Handle test failure better"
diff --git a/compos/aidl/com/android/compos/ICompOsService.aidl b/compos/aidl/com/android/compos/ICompOsService.aidl
index 48a46b1..9cf99be 100644
--- a/compos/aidl/com/android/compos/ICompOsService.aidl
+++ b/compos/aidl/com/android/compos/ICompOsService.aidl
@@ -19,6 +19,18 @@
/** {@hide} */
interface ICompOsService {
/**
+ * Initializes system properties. ART expects interesting properties that have to be passed from
+ * Android. The API client should call this method once with all desired properties, since once
+ * the call completes, the service is considered initialized and cannot be re-initialized again.
+ *
+ * <p>If the initialization failed, Microdroid may already have some properties set. It is up to
+ * the service to reject further calls by the client.
+ *
+ * <p>The service may reject unrecognized names, but it does not interpret values.
+ */
+ void initializeSystemProperties(in String[] names, in String[] values);
+
+ /**
* What type of compilation to perform.
*/
@Backing(type="int")
diff --git a/compos/common/odrefresh.rs b/compos/common/odrefresh.rs
index 390e50c..2d7635b 100644
--- a/compos/common/odrefresh.rs
+++ b/compos/common/odrefresh.rs
@@ -35,6 +35,10 @@
/// The directory under ODREFRESH_OUTPUT_ROOT_DIR where the current (active) artifacts are stored
pub const CURRENT_ARTIFACTS_SUBDIR: &str = "dalvik-cache";
+/// Prefixes of system properties that are interested to odrefresh and dex2oat.
+const ALLOWLIST_SYSTEM_PROPERTY_PREFIXES: &[&str] =
+ &["dalvik.vm.", "ro.dalvik.vm.", "persist.device_config.runtime_native_boot."];
+
// The highest "standard" exit code defined in sysexits.h (as EX__MAX); odrefresh error codes
// start above here to avoid clashing.
// TODO: What if this changes?
@@ -63,3 +67,13 @@
.ok_or_else(|| anyhow!("Unexpected odrefresh exit code: {}", exit_code))
}
}
+
+/// Returns whether the system property name is interesting to odrefresh and dex2oat.
+pub fn is_system_property_interesting(name: &str) -> bool {
+ for prefix in ALLOWLIST_SYSTEM_PROPERTY_PREFIXES {
+ if name.starts_with(prefix) {
+ return true;
+ }
+ }
+ false
+}
diff --git a/compos/composd/src/odrefresh_task.rs b/compos/composd/src/odrefresh_task.rs
index e06e5fe..51e866f 100644
--- a/compos/composd/src/odrefresh_task.rs
+++ b/compos/composd/src/odrefresh_task.rs
@@ -27,7 +27,9 @@
use compos_aidl_interface::aidl::com::android::compos::ICompOsService::{
CompilationMode::CompilationMode, ICompOsService,
};
-use compos_common::odrefresh::{ExitCode, ODREFRESH_OUTPUT_ROOT_DIR};
+use compos_common::odrefresh::{
+ is_system_property_interesting, ExitCode, ODREFRESH_OUTPUT_ROOT_DIR,
+};
use log::{error, info, warn};
use rustutils::system_properties;
use std::fs::{remove_dir_all, File, OpenOptions};
@@ -124,6 +126,16 @@
compilation_mode: CompilationMode,
target_dir_name: &str,
) -> Result<ExitCode> {
+ let mut names = Vec::new();
+ let mut values = Vec::new();
+ system_properties::foreach(|name, value| {
+ if is_system_property_interesting(name) {
+ names.push(name.to_owned());
+ values.push(value.to_owned());
+ }
+ })?;
+ service.initializeSystemProperties(&names, &values).context("initialize system properties")?;
+
let output_root = Path::new(ODREFRESH_OUTPUT_ROOT_DIR);
// We need to remove the target directory because odrefresh running in compos will create it
diff --git a/compos/src/compsvc.rs b/compos/src/compsvc.rs
index e21aa7d..91415bb 100644
--- a/compos/src/compsvc.rs
+++ b/compos/src/compsvc.rs
@@ -19,9 +19,14 @@
//! actual compiler.
use anyhow::{bail, Context, Result};
+use binder_common::new_binder_exception;
+use log::error;
+use rustutils::system_properties;
use std::default::Default;
use std::fs::read_dir;
+use std::iter::zip;
use std::path::{Path, PathBuf};
+use std::sync::RwLock;
use crate::artifact_signer::ArtifactSigner;
use crate::compilation::{odrefresh, OdrefreshContext};
@@ -29,25 +34,73 @@
use compos_aidl_interface::aidl::com::android::compos::ICompOsService::{
BnCompOsService, CompilationMode::CompilationMode, ICompOsService,
};
-use compos_aidl_interface::binder::{BinderFeatures, Interface, Result as BinderResult, Strong};
+use compos_aidl_interface::binder::{
+ BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Strong,
+};
use compos_common::binder::to_binder_result;
-use compos_common::odrefresh::ODREFRESH_PATH;
+use compos_common::odrefresh::{is_system_property_interesting, ODREFRESH_PATH};
const AUTHFS_SERVICE_NAME: &str = "authfs_service";
/// Constructs a binder object that implements ICompOsService.
pub fn new_binder() -> Result<Strong<dyn ICompOsService>> {
- let service = CompOsService { odrefresh_path: PathBuf::from(ODREFRESH_PATH) };
+ let service = CompOsService {
+ odrefresh_path: PathBuf::from(ODREFRESH_PATH),
+ initialized: RwLock::new(None),
+ };
Ok(BnCompOsService::new_binder(service, BinderFeatures::default()))
}
struct CompOsService {
odrefresh_path: PathBuf,
+
+ /// A locked protected tri-state.
+ /// * None: uninitialized
+ /// * Some(true): initialized successfully
+ /// * Some(false): failed to initialize
+ initialized: RwLock<Option<bool>>,
}
impl Interface for CompOsService {}
impl ICompOsService for CompOsService {
+ fn initializeSystemProperties(&self, names: &[String], values: &[String]) -> BinderResult<()> {
+ let mut initialized = self.initialized.write().unwrap();
+ if initialized.is_some() {
+ return Err(new_binder_exception(
+ ExceptionCode::ILLEGAL_STATE,
+ format!("Already initialized: {:?}", initialized),
+ ));
+ }
+ *initialized = Some(false);
+
+ if names.len() != values.len() {
+ return Err(new_binder_exception(
+ ExceptionCode::ILLEGAL_ARGUMENT,
+ format!(
+ "Received inconsistent number of keys ({}) and values ({})",
+ names.len(),
+ values.len()
+ ),
+ ));
+ }
+ for (name, value) in zip(names, values) {
+ if !is_system_property_interesting(name) {
+ return Err(new_binder_exception(
+ ExceptionCode::ILLEGAL_ARGUMENT,
+ format!("Received invalid system property {}", &name),
+ ));
+ }
+ let result = system_properties::write(name, value);
+ if result.is_err() {
+ error!("Failed to setprop {}", &name);
+ return to_binder_result(result);
+ }
+ }
+ *initialized = Some(true);
+ Ok(())
+ }
+
fn odrefresh(
&self,
compilation_mode: CompilationMode,
@@ -58,6 +111,14 @@
zygote_arch: &str,
system_server_compiler_filter: &str,
) -> BinderResult<i8> {
+ let initialized = *self.initialized.read().unwrap();
+ if !initialized.unwrap_or(false) {
+ return Err(new_binder_exception(
+ ExceptionCode::ILLEGAL_STATE,
+ "Service has not been initialized",
+ ));
+ }
+
let context = to_binder_result(OdrefreshContext::new(
compilation_mode,
system_dir_fd,
diff --git a/pvmfw/idmap.S b/pvmfw/idmap.S
index f1df6cc..62555f9 100644
--- a/pvmfw/idmap.S
+++ b/pvmfw/idmap.S
@@ -39,12 +39,14 @@
idmap:
/* level 1 */
.quad .L_BLOCK_DEV | 0x0 // 1 GB of device mappings
- .quad .L_BLOCK_DEV | 0x40000000 // Another 1 GB of device mapppings
- .quad .L_TT_TYPE_TABLE + 0f // up to 1 GB of DRAM
+ .quad .L_TT_TYPE_TABLE + 0f // Unmapped device memory, and pVM firmware
+ .quad .L_TT_TYPE_TABLE + 1f // up to 1 GB of DRAM
.fill 509, 8, 0x0 // 509 GB of remaining VA space
/* level 2 */
-0: .quad .L_BLOCK_RO | 0x80000000 // DT provided by VMM
- .quad .L_BLOCK_MEM_XIP | 0x80200000 // 2 MB of DRAM containing image
- .quad .L_BLOCK_MEM | 0x80400000 // 2 MB of writable DRAM
+0: .fill 511, 8, 0x0
+ .quad .L_BLOCK_MEM_XIP | 0x7fe00000 // pVM firmware image
+1: .quad .L_BLOCK_RO | 0x80000000 // DT provided by VMM
+ .quad .L_BLOCK_RO | 0x80200000 // 2 MB of DRAM containing payload image
+ .quad .L_BLOCK_MEM | 0x80400000 // Writable memory for stack, heap &c.
.fill 509, 8, 0x0
diff --git a/pvmfw/image.ld b/pvmfw/image.ld
index 4655f68..e122c72 100644
--- a/pvmfw/image.ld
+++ b/pvmfw/image.ld
@@ -16,8 +16,8 @@
MEMORY
{
+ image : ORIGIN = 0x7fe00000, LENGTH = 2M
dtb_region : ORIGIN = 0x80000000, LENGTH = 2M
- image : ORIGIN = 0x80200000, LENGTH = 2M
writable_data : ORIGIN = 0x80400000, LENGTH = 2M
}
diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs
index d98ea8e..280e1ce 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -24,6 +24,10 @@
main!(main);
/// Entry point for pVM firmware.
-pub fn main() {
- println!("Hello world");
+pub fn main(fdt_address: u64, payload_start: u64, payload_size: u64, arg3: u64) {
+ println!("pVM firmware");
+ println!(
+ "fdt_address={:#010x}, payload_start={:#010x}, payload_size={:#010x}, x3={:#010x}",
+ fdt_address, payload_start, payload_size, arg3,
+ );
}
diff --git a/tests/hostside/AndroidTest.xml b/tests/hostside/AndroidTest.xml
index 79428ce..5c3e5d1 100644
--- a/tests/hostside/AndroidTest.xml
+++ b/tests/hostside/AndroidTest.xml
@@ -19,6 +19,12 @@
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ <!-- Permission checks are bypassed if shell is root -->
+ <option name="force-root" value="false"/>
+ </target_preparer>
+
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="MicrodroidHostTestCases.jar" />
</test>
diff --git a/vmbase/entry.S b/vmbase/entry.S
index a12e1aa..490e841 100644
--- a/vmbase/entry.S
+++ b/vmbase/entry.S
@@ -74,31 +74,30 @@
.set .Lsctlrval, .Lsctlrval | .L_SCTLR_ELx_I | .L_SCTLR_EL1_SPAN | .L_SCTLR_EL1_RES1 | .L_SCTLR_EL1_WXN
/**
- * This is a generic entry point for an image. It carries out the operations
- * required to prepare the loaded image to be run. Specifically, it zeroes the
- * bss section using registers x25 and above, prepares the stack, enables
- * floating point, and sets up the exception vector.
+ * This is a generic entry point for an image. It carries out the operations required to prepare the
+ * loaded image to be run. Specifically, it zeroes the bss section using registers x25 and above,
+ * prepares the stack, enables floating point, and sets up the exception vector. It preserves x0-x3
+ * for the Rust entry point, as these may contain boot parameters.
*/
.section .init.entry, "ax"
.global entry
entry:
- /* Enable MMU and caches. */
+ /* Load and apply the memory management configuration, ready to enable MMU and caches. */
- /*
- * Load and apply the memory management configuration.
- */
- adrp x1, idmap
- mov_i x2, .Lmairval
- mov_i x3, .Ltcrval
- mov_i x4, .Lsctlrval
+ adrp x30, idmap
+ msr ttbr0_el1, x30
+ mov_i x30, .Lmairval
+ msr mair_el1, x30
+
+ mov_i x30, .Ltcrval
/* Copy the supported PA range into TCR_EL1.IPS. */
- mrs x6, id_aa64mmfr0_el1
- bfi x3, x6, #32, #4
+ mrs x29, id_aa64mmfr0_el1
+ bfi x30, x29, #32, #4
- msr ttbr0_el1, x1
- msr mair_el1, x2
- msr tcr_el1, x3
+ msr tcr_el1, x30
+
+ mov_i x30, .Lsctlrval
/*
* Ensure everything before this point has completed, then invalidate any potentially stale
@@ -111,10 +110,9 @@
isb
/*
- * Configure sctlr_el1 to enable MMU and cache and don't proceed until
- * this has completed.
+ * Configure sctlr_el1 to enable MMU and cache and don't proceed until this has completed.
*/
- msr sctlr_el1, x4
+ msr sctlr_el1, x30
isb
/* Disable trapping floating point access in EL1. */
diff --git a/vmbase/example/Android.bp b/vmbase/example/Android.bp
index 4cc4bf3..9c19693 100644
--- a/vmbase/example/Android.bp
+++ b/vmbase/example/Android.bp
@@ -13,6 +13,7 @@
"libcore.rust_sysroot",
],
rustlibs: [
+ "libbuddy_system_allocator",
"libvmbase",
],
enabled: false,
diff --git a/vmbase/example/src/main.rs b/vmbase/example/src/main.rs
index bbb64d9..3b1786c 100644
--- a/vmbase/example/src/main.rs
+++ b/vmbase/example/src/main.rs
@@ -16,14 +16,139 @@
#![no_main]
#![no_std]
+#![feature(default_alloc_error_handler)]
mod exceptions;
+extern crate alloc;
+
+use alloc::{vec, vec::Vec};
+use buddy_system_allocator::LockedHeap;
use vmbase::{main, println};
+static INITIALISED_DATA: [u32; 4] = [1, 2, 3, 4];
+static mut ZEROED_DATA: [u32; 10] = [0; 10];
+static mut MUTABLE_DATA: [u32; 4] = [1, 2, 3, 4];
+
+#[global_allocator]
+static HEAP_ALLOCATOR: LockedHeap<32> = LockedHeap::<32>::new();
+
+static mut HEAP: [u8; 65536] = [0; 65536];
+
main!(main);
/// Entry point for VM bootloader.
-pub fn main() {
+pub fn main(arg0: u64, arg1: u64, arg2: u64, arg3: u64) {
println!("Hello world");
+ println!("x0={:#010x}, x1={:#010x}, x2={:#010x}, x3={:#010x}", arg0, arg1, arg2, arg3);
+ print_addresses();
+ check_data();
+
+ unsafe {
+ HEAP_ALLOCATOR.lock().init(&mut HEAP as *mut u8 as usize, HEAP.len());
+ }
+
+ check_alloc();
+}
+
+fn print_addresses() {
+ unsafe {
+ println!(
+ "dtb: {:#010x}-{:#010x} ({} bytes)",
+ &dtb_begin as *const u8 as usize,
+ &dtb_end as *const u8 as usize,
+ &dtb_end as *const u8 as usize - &dtb_begin as *const u8 as usize,
+ );
+ println!(
+ "text: {:#010x}-{:#010x} ({} bytes)",
+ &text_begin as *const u8 as usize,
+ &text_end as *const u8 as usize,
+ &text_end as *const u8 as usize - &text_begin as *const u8 as usize,
+ );
+ println!(
+ "rodata: {:#010x}-{:#010x} ({} bytes)",
+ &rodata_begin as *const u8 as usize,
+ &rodata_end as *const u8 as usize,
+ &rodata_end as *const u8 as usize - &rodata_begin as *const u8 as usize,
+ );
+ println!(
+ "data: {:#010x}-{:#010x} ({} bytes, loaded at {:#010x})",
+ &data_begin as *const u8 as usize,
+ &data_end as *const u8 as usize,
+ &data_end as *const u8 as usize - &data_begin as *const u8 as usize,
+ &data_lma as *const u8 as usize,
+ );
+ println!(
+ "bss: {:#010x}-{:#010x} ({} bytes)",
+ &bss_begin as *const u8 as usize,
+ &bss_end as *const u8 as usize,
+ &bss_end as *const u8 as usize - &bss_begin as *const u8 as usize,
+ );
+ println!(
+ "boot_stack: {:#010x}-{:#010x} ({} bytes)",
+ &boot_stack_begin as *const u8 as usize,
+ &boot_stack_end as *const u8 as usize,
+ &boot_stack_end as *const u8 as usize - &boot_stack_begin as *const u8 as usize,
+ );
+ }
+}
+
+fn check_data() {
+ println!("INITIALISED_DATA: {:#010x}", &INITIALISED_DATA as *const u32 as usize);
+ unsafe {
+ println!("ZEROED_DATA: {:#010x}", &ZEROED_DATA as *const u32 as usize);
+ println!("MUTABLE_DATA: {:#010x}", &MUTABLE_DATA as *const u32 as usize);
+ println!("HEAP: {:#010x}", &HEAP as *const u8 as usize);
+ }
+
+ assert_eq!(INITIALISED_DATA[0], 1);
+ assert_eq!(INITIALISED_DATA[1], 2);
+ assert_eq!(INITIALISED_DATA[2], 3);
+ assert_eq!(INITIALISED_DATA[3], 4);
+
+ unsafe {
+ for element in ZEROED_DATA.iter() {
+ assert_eq!(*element, 0);
+ }
+ ZEROED_DATA[0] = 13;
+ assert_eq!(ZEROED_DATA[0], 13);
+ ZEROED_DATA[0] = 0;
+ assert_eq!(ZEROED_DATA[0], 0);
+
+ assert_eq!(MUTABLE_DATA[0], 1);
+ assert_eq!(MUTABLE_DATA[1], 2);
+ assert_eq!(MUTABLE_DATA[2], 3);
+ assert_eq!(MUTABLE_DATA[3], 4);
+ MUTABLE_DATA[0] += 41;
+ assert_eq!(MUTABLE_DATA[0], 42);
+ }
+ println!("Data looks good");
+}
+
+fn check_alloc() {
+ println!("Allocating a Vec...");
+ let mut vector: Vec<u32> = vec![1, 2, 3, 4];
+ assert_eq!(vector[0], 1);
+ assert_eq!(vector[1], 2);
+ assert_eq!(vector[2], 3);
+ assert_eq!(vector[3], 4);
+ vector[2] = 42;
+ assert_eq!(vector[2], 42);
+ println!("Vec seems to work.");
+}
+
+extern "C" {
+ static dtb_begin: u8;
+ static dtb_end: u8;
+ static text_begin: u8;
+ static text_end: u8;
+ static rodata_begin: u8;
+ static rodata_end: u8;
+ static data_begin: u8;
+ static data_end: u8;
+ static data_lma: u8;
+ static bss_begin: u8;
+ static bss_end: u8;
+ static boot_stack_begin: u8;
+ static boot_stack_end: u8;
}
diff --git a/vmbase/src/entry.rs b/vmbase/src/entry.rs
index dd7f6db..1510ae2 100644
--- a/vmbase/src/entry.rs
+++ b/vmbase/src/entry.rs
@@ -18,17 +18,17 @@
/// This is the entry point to the Rust code, called from the binary entry point in `entry.S`.
#[no_mangle]
-extern "C" fn rust_entry() -> ! {
+extern "C" fn rust_entry(x0: u64, x1: u64, x2: u64, x3: u64) -> ! {
console::init();
unsafe {
- main();
+ main(x0, x1, x2, x3);
}
shutdown();
}
extern "Rust" {
/// Main function provided by the application using the `main!` macro.
- fn main();
+ fn main(arg0: u64, arg1: u64, arg2: u64, arg3: u64);
}
/// Marks the main function of the binary.
@@ -49,9 +49,9 @@
($name:path) => {
// Export a symbol with a name matching the extern declaration above.
#[export_name = "main"]
- fn __main() {
+ fn __main(arg0: u64, arg1: u64, arg2: u64, arg3: u64) {
// Ensure that the main function provided by the application has the correct type.
- $name()
+ $name(arg0, arg1, arg2, arg3)
}
};
}