Run odrefresh in composd
This is far from finished, but it is at least started. This currently
fails when pvm_exec tries to create a vsock; instead it will need to
request one from composd.
Test: adb shell apex/com.android.compos/bin/composd_cmd
Bug: 186126194
Change-Id: Ic193ddd3835be3daf70b15e78c56c0ccb98e7a1f
diff --git a/compos/composd/Android.bp b/compos/composd/Android.bp
index 007eda9..5c968b8 100644
--- a/compos/composd/Android.bp
+++ b/compos/composd/Android.bp
@@ -6,6 +6,7 @@
name: "composd",
srcs: ["src/composd_main.rs"],
edition: "2018",
+ prefer_rlib: true,
rustlibs: [
"android.system.composd-rust",
"compos_aidl_interface-rust",
@@ -13,9 +14,10 @@
"libanyhow",
"libbinder_rs",
"libcompos_common",
+ "libnum_traits",
"liblog_rust",
],
- prefer_rlib: true,
+ proc_macros: ["libnum_derive"],
apex_available: [
"com.android.compos",
],
diff --git a/compos/composd/aidl/android/system/composd/IIsolatedCompilationService.aidl b/compos/composd/aidl/android/system/composd/IIsolatedCompilationService.aidl
index 0dd5b6f..9240bc6 100644
--- a/compos/composd/aidl/android/system/composd/IIsolatedCompilationService.aidl
+++ b/compos/composd/aidl/android/system/composd/IIsolatedCompilationService.aidl
@@ -16,6 +16,6 @@
package android.system.composd;
interface IIsolatedCompilationService {
- // TODO: Add real methods
- void doSomething();
+ /// Run "odrefresh --force-compile" in CompOS
+ void runForcedCompile();
}
diff --git a/compos/composd/src/compos_instance.rs b/compos/composd/src/compos_instance.rs
new file mode 100644
index 0000000..e30a8b3
--- /dev/null
+++ b/compos/composd/src/compos_instance.rs
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Starts and manages instances of the CompOS VM.
+
+use anyhow::{Context, Result};
+use compos_aidl_interface::aidl::com::android::compos::ICompOsService::ICompOsService;
+use compos_aidl_interface::binder::Strong;
+use compos_common::compos_client::VmInstance;
+use compos_common::{COMPOS_DATA_ROOT, CURRENT_DIR, INSTANCE_IMAGE_FILE, PRIVATE_KEY_BLOB_FILE};
+use std::fs;
+use std::path::PathBuf;
+
+#[allow(dead_code)]
+pub struct CompOsInstance {
+ instance: VmInstance,
+ service: Strong<dyn ICompOsService>,
+}
+
+impl CompOsInstance {
+ pub fn start_current_instance() -> Result<CompOsInstance> {
+ let instance_image: PathBuf =
+ [COMPOS_DATA_ROOT, CURRENT_DIR, INSTANCE_IMAGE_FILE].iter().collect();
+
+ let instance = VmInstance::start(&instance_image).context("Starting VM")?;
+ let service = instance.get_service().context("Connecting to CompOS")?;
+
+ let key_blob: PathBuf =
+ [COMPOS_DATA_ROOT, CURRENT_DIR, PRIVATE_KEY_BLOB_FILE].iter().collect();
+ let key_blob = fs::read(key_blob).context("Reading private key")?;
+ service.initializeSigningKey(&key_blob).context("Loading key")?;
+
+ Ok(CompOsInstance { instance, service })
+ }
+
+ pub fn cid(&self) -> i32 {
+ self.instance.cid()
+ }
+}
diff --git a/compos/composd/src/composd_main.rs b/compos/composd/src/composd_main.rs
index f674448..33da889 100644
--- a/compos/composd/src/composd_main.rs
+++ b/compos/composd/src/composd_main.rs
@@ -18,6 +18,8 @@
//! responsible for managing the lifecycle of the CompOS VM instances, providing key management for
//! them, and orchestrating trusted compilation.
+mod compos_instance;
+mod odrefresh;
mod service;
use android_system_composd::binder::{register_lazy_service, ProcessState};
@@ -29,6 +31,8 @@
android_logger::Config::default().with_tag("composd").with_min_level(log::Level::Info),
);
+ ProcessState::start_thread_pool();
+
let service = service::new_binder();
register_lazy_service("android.system.composd", service.as_binder())
.context("Registering service")?;
diff --git a/compos/composd/src/odrefresh.rs b/compos/composd/src/odrefresh.rs
new file mode 100644
index 0000000..c0042f0
--- /dev/null
+++ b/compos/composd/src/odrefresh.rs
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Handle the details of executing odrefresh to generate compiled artifacts.
+
+use anyhow::{bail, Context, Result};
+use num_derive::FromPrimitive;
+use num_traits::FromPrimitive;
+use std::process::Command;
+
+// TODO: What if this changes?
+const EX_MAX: i32 = 78;
+const ODREFRESH_BIN: &str = "/apex/com.android.art/bin/odrefresh";
+
+#[derive(Debug, PartialEq, Eq, FromPrimitive)]
+#[repr(i32)]
+pub enum ExitCode {
+ // Copied from art/odrefresh/include/odrefresh/odrefresh.h
+ Okay = 0i32,
+ CompilationRequired = EX_MAX + 1,
+ CompilationSuccess = EX_MAX + 2,
+ CompilationFailed = EX_MAX + 3,
+ CleanupFailed = EX_MAX + 4,
+}
+
+pub fn run_forced_compile(cid: i32) -> Result<ExitCode> {
+ // We don`t need to capture stdout/stderr - odrefresh writes to the log
+ let mut odrefresh = Command::new(ODREFRESH_BIN)
+ .arg(format!("--use-compilation-os={}", cid))
+ .arg("--force-compile")
+ .spawn()
+ .context("Running odrefresh")?;
+
+ // TODO: timeout?
+ let status = odrefresh.wait()?;
+
+ if let Some(exit_code) = status.code().and_then(FromPrimitive::from_i32) {
+ Ok(exit_code)
+ } else {
+ bail!("odrefresh exited with {}", status)
+ }
+}
diff --git a/compos/composd/src/service.rs b/compos/composd/src/service.rs
index 8fe28ec..7fc9ab0 100644
--- a/compos/composd/src/service.rs
+++ b/compos/composd/src/service.rs
@@ -17,10 +17,15 @@
//! Implementation of IIsolatedCompilationService, called from system server when compilation is
//! desired.
+use crate::compos_instance::CompOsInstance;
+use crate::odrefresh;
use android_system_composd::aidl::android::system::composd::IIsolatedCompilationService::{
BnIsolatedCompilationService, IIsolatedCompilationService,
};
-use android_system_composd::binder::{self, BinderFeatures, Interface, Strong};
+use android_system_composd::binder::{self, BinderFeatures, Interface, Status, Strong};
+use anyhow::{bail, Context, Result};
+use log::{error, info};
+use std::ffi::CString;
pub struct IsolatedCompilationService {}
@@ -29,12 +34,35 @@
BnIsolatedCompilationService::new_binder(service, BinderFeatures::default())
}
-impl IsolatedCompilationService {}
-
impl Interface for IsolatedCompilationService {}
impl IIsolatedCompilationService for IsolatedCompilationService {
- fn doSomething(&self) -> binder::Result<()> {
+ fn runForcedCompile(&self) -> binder::Result<()> {
+ to_binder_result(self.do_run_forced_compile())
+ }
+}
+
+fn to_binder_result<T>(result: Result<T>) -> binder::Result<T> {
+ result.map_err(|e| {
+ error!("Returning binder error: {:#}", e);
+ Status::new_service_specific_error(-1, CString::new(format!("{:#}", e)).ok().as_deref())
+ })
+}
+
+impl IsolatedCompilationService {
+ fn do_run_forced_compile(&self) -> Result<()> {
+ info!("runForcedCompile");
+
+ // TODO: Create instance if need be, handle instance failure, prevent
+ // multiple instances running
+ let comp_os = CompOsInstance::start_current_instance().context("Starting CompOS")?;
+
+ let exit_code = odrefresh::run_forced_compile(comp_os.cid())?;
+
+ if exit_code != odrefresh::ExitCode::CompilationSuccess {
+ bail!("Unexpected odrefresh result: {:?}", exit_code);
+ }
+
Ok(())
}
}