Initialize compsvc with allowlisted system properties
Bug: 231579544
Test: composd_cmd test-compile, see properties in the VM
Change-Id: Ia8b37236bb7039434d464be924aca5ee4c6bd42f
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,