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/apex/Android.bp b/compos/apex/Android.bp
index ada0976..547fd44 100644
--- a/compos/apex/Android.bp
+++ b/compos/apex/Android.bp
@@ -41,6 +41,7 @@
"compos_key_cmd",
"compos_verify_key",
"composd",
+ "composd_cmd",
"compsvc",
"pvm_exec",
],
diff --git a/compos/apex/composd.rc b/compos/apex/composd.rc
index 099a346..3e2efb1 100644
--- a/compos/apex/composd.rc
+++ b/compos/apex/composd.rc
@@ -14,7 +14,7 @@
service composd /apex/com.android.compos/bin/composd
class main
- user system
+ user root
group system
interface aidl android.system.composd
disabled
diff --git a/compos/common/compos_client.rs b/compos/common/compos_client.rs
index 80cf05a..03cc331 100644
--- a/compos/common/compos_client.rs
+++ b/compos/common/compos_client.rs
@@ -47,7 +47,6 @@
pub struct VmInstance {
#[allow(dead_code)] // Keeps the vm alive even if we don`t touch it
vm: Strong<dyn IVirtualMachine>,
- #[allow(dead_code)] // Likely to be useful
cid: i32,
}
@@ -132,6 +131,11 @@
FromIBinder::try_from(ibinder).context("Connecting to CompOS service")
}
+
+ /// Return the CID of the VM.
+ pub fn cid(&self) -> i32 {
+ self.cid
+ }
}
struct VsockFactory<'a> {
diff --git a/compos/common/lib.rs b/compos/common/lib.rs
index 081f086..6bea62c 100644
--- a/compos/common/lib.rs
+++ b/compos/common/lib.rs
@@ -27,3 +27,20 @@
/// The root of the data directory available for private use by the CompOS APEX.
pub const COMPOS_DATA_ROOT: &str = "/data/misc/apexdata/com.android.compos";
+
+/// The sub-directory where we store information relating to the pending instance
+/// of CompOS (based on staged APEXes).
+pub const PENDING_DIR: &str = "pending";
+
+/// The sub-directory where we store information relating to the current instance
+/// of CompOS (based on active APEXes).
+pub const CURRENT_DIR: &str = "current";
+
+/// The file that holds the encrypted private key for a CompOS instance.
+pub const PRIVATE_KEY_BLOB_FILE: &str = "key.blob";
+
+/// The file that holds the public key for a CompOS instance.
+pub const PUBLIC_KEY_FILE: &str = "key.pubkey";
+
+/// The file that holds the instance image for a CompOS instance.
+pub const INSTANCE_IMAGE_FILE: &str = "instance.img";
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(())
}
}
diff --git a/compos/composd_cmd/Android.bp b/compos/composd_cmd/Android.bp
new file mode 100644
index 0000000..5fef86f
--- /dev/null
+++ b/compos/composd_cmd/Android.bp
@@ -0,0 +1,18 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_binary {
+ name: "composd_cmd",
+ srcs: ["composd_cmd.rs"],
+ edition: "2018",
+ rustlibs: [
+ "android.system.composd-rust",
+ "libanyhow",
+ "libbinder_rs",
+ ],
+ prefer_rlib: true,
+ apex_available: [
+ "com.android.compos",
+ ],
+}
diff --git a/compos/composd_cmd/composd_cmd.rs b/compos/composd_cmd/composd_cmd.rs
new file mode 100644
index 0000000..e4884e3
--- /dev/null
+++ b/compos/composd_cmd/composd_cmd.rs
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+//! Simple command-line tool to drive composd for testing and debugging.
+
+use android_system_composd::{
+ aidl::android::system::composd::IIsolatedCompilationService::IIsolatedCompilationService,
+ binder::{wait_for_interface, ProcessState},
+};
+use anyhow::{Context, Result};
+
+fn main() -> Result<()> {
+ ProcessState::start_thread_pool();
+
+ let service = wait_for_interface::<dyn IIsolatedCompilationService>("android.system.composd")
+ .context("Failed to connect to composd service")?;
+
+ service.runForcedCompile().context("Compilation failed")?;
+
+ println!("All Ok!");
+
+ Ok(())
+}
diff --git a/compos/verify_key/verify_key.rs b/compos/verify_key/verify_key.rs
index 2e3d206..8439b97 100644
--- a/compos/verify_key/verify_key.rs
+++ b/compos/verify_key/verify_key.rs
@@ -20,17 +20,14 @@
use anyhow::{bail, Context, Result};
use compos_aidl_interface::binder::ProcessState;
use compos_common::compos_client::VmInstance;
-use compos_common::COMPOS_DATA_ROOT;
+use compos_common::{
+ COMPOS_DATA_ROOT, CURRENT_DIR, INSTANCE_IMAGE_FILE, PENDING_DIR, PRIVATE_KEY_BLOB_FILE,
+ PUBLIC_KEY_FILE,
+};
use std::fs::{self, File};
use std::io::Read;
use std::path::{Path, PathBuf};
-const CURRENT_DIR: &str = "current";
-const PENDING_DIR: &str = "pending";
-const PRIVATE_KEY_BLOB_FILE: &str = "key.blob";
-const PUBLIC_KEY_FILE: &str = "key.pubkey";
-const INSTANCE_IMAGE_FILE: &str = "instance.img";
-
const MAX_FILE_SIZE_BYTES: u64 = 8 * 1024;
fn main() -> Result<()> {