compos: mount BuildManifestSystemExt.apk if exists
To specify the extra APK, we have to add two new VM config JSONs because
the APK may not exist, and there is no way to specify the config
dynamically.
Change VmParameters in order to derive the config path from two
variables at a more consistent place. As a result, there's no more
"default" config.
Bug: 246000387
Test: 1. manually add a jar from system_ext to SYSTEMSERVERCLASSPATH
2. boot the VM, saw 2 directories in /mnt/extra-apk/
(and with more local WIP changes, ComposHostTestCases passed)
Change-Id: I8aac49e0b347560fb65d8a8330e4333a29d90433
diff --git a/compos/apk/assets/vm_config_system_ext.json b/compos/apk/assets/vm_config_system_ext.json
new file mode 100644
index 0000000..e60dee7
--- /dev/null
+++ b/compos/apk/assets/vm_config_system_ext.json
@@ -0,0 +1,33 @@
+{
+ "version": 1,
+ "os": {
+ "name": "microdroid"
+ },
+ "task": {
+ "type": "executable",
+ "command": "/apex/com.android.compos/bin/compsvc"
+ },
+ "extra_apks": [
+ {
+ "path": "/system/etc/security/fsverity/BuildManifest.apk"
+ },
+ {
+ "path": "/system_ext/etc/security/fsverity/BuildManifestSystemExt.apk"
+ }
+ ],
+ "apexes": [
+ {
+ "name": "com.android.art"
+ },
+ {
+ "name": "com.android.compos"
+ },
+ {
+ "name": "com.android.sdkext"
+ },
+ {
+ "name": "{CLASSPATH}"
+ }
+ ],
+ "export_tombstones": true
+}
diff --git a/compos/apk/assets/vm_config_system_ext_staged.json b/compos/apk/assets/vm_config_system_ext_staged.json
new file mode 100644
index 0000000..99a4160
--- /dev/null
+++ b/compos/apk/assets/vm_config_system_ext_staged.json
@@ -0,0 +1,34 @@
+{
+ "version": 1,
+ "os": {
+ "name": "microdroid"
+ },
+ "task": {
+ "type": "executable",
+ "command": "/apex/com.android.compos/bin/compsvc"
+ },
+ "prefer_staged": true,
+ "extra_apks": [
+ {
+ "path": "/system/etc/security/fsverity/BuildManifest.apk"
+ },
+ {
+ "path": "/system_ext/etc/security/fsverity/BuildManifestSystemExt.apk"
+ }
+ ],
+ "apexes": [
+ {
+ "name": "com.android.art"
+ },
+ {
+ "name": "com.android.compos"
+ },
+ {
+ "name": "com.android.sdkext"
+ },
+ {
+ "name": "{CLASSPATH}"
+ }
+ ],
+ "export_tombstones": true
+}
diff --git a/compos/common/compos_client.rs b/compos/common/compos_client.rs
index 5ea5c06..49396d7 100644
--- a/compos/common/compos_client.rs
+++ b/compos/common/compos_client.rs
@@ -17,7 +17,10 @@
//! Support for starting CompOS in a VM and connecting to the service
use crate::timeouts::TIMEOUTS;
-use crate::{COMPOS_APEX_ROOT, COMPOS_DATA_ROOT, COMPOS_VSOCK_PORT, DEFAULT_VM_CONFIG_PATH};
+use crate::{
+ get_vm_config_path, BUILD_MANIFEST_APK_PATH, BUILD_MANIFEST_SYSTEM_EXT_APK_PATH,
+ COMPOS_APEX_ROOT, COMPOS_DATA_ROOT, COMPOS_VSOCK_PORT,
+};
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
IVirtualizationService::IVirtualizationService,
VirtualMachineAppConfig::{DebugLevel::DebugLevel, VirtualMachineAppConfig},
@@ -47,10 +50,10 @@
pub cpus: Option<NonZeroU32>,
/// List of task profiles to apply to the VM
pub task_profiles: Vec<String>,
- /// If present, overrides the path to the VM config JSON file
- pub config_path: Option<String>,
/// If present, overrides the amount of RAM to give the VM
pub memory_mib: Option<i32>,
+ /// Whether the VM prefers staged APEXes or activated ones (false; default)
+ pub prefer_staged: bool,
}
impl ComposClient {
@@ -60,6 +63,7 @@
instance_image: File,
idsig: &Path,
idsig_manifest_apk: &Path,
+ idsig_manifest_ext_apk: &Path,
parameters: &VmParameters,
) -> Result<Self> {
let protected_vm = want_protected_vm()?;
@@ -74,11 +78,27 @@
let apk_fd = ParcelFileDescriptor::new(apk_fd);
let idsig_fd = prepare_idsig(service, &apk_fd, idsig)?;
- let manifest_apk_fd = File::open("/system/etc/security/fsverity/BuildManifest.apk")
+ let manifest_apk_fd = File::open(BUILD_MANIFEST_APK_PATH)
.context("Failed to open build manifest APK file")?;
let manifest_apk_fd = ParcelFileDescriptor::new(manifest_apk_fd);
let idsig_manifest_apk_fd = prepare_idsig(service, &manifest_apk_fd, idsig_manifest_apk)?;
+ // Prepare a few things based on whether /system_ext exists, including:
+ // 1. generate the additional idsig FD for the APK from /system_ext, then pass to VS
+ // 2. select the correct VM config json
+ let (extra_idsigs, has_system_ext) =
+ if let Ok(manifest_ext_apk_fd) = File::open(BUILD_MANIFEST_SYSTEM_EXT_APK_PATH) {
+ // Optional idsig in /system_ext is found, so prepare additionally.
+ let manifest_ext_apk_fd = ParcelFileDescriptor::new(manifest_ext_apk_fd);
+ let idsig_manifest_ext_apk_fd =
+ prepare_idsig(service, &manifest_ext_apk_fd, idsig_manifest_ext_apk)?;
+
+ (vec![idsig_manifest_apk_fd, idsig_manifest_ext_apk_fd], true)
+ } else {
+ (vec![idsig_manifest_apk_fd], false)
+ };
+ let config_path = get_vm_config_path(has_system_ext, parameters.prefer_staged);
+
let debug_level = match (protected_vm, parameters.debug_mode) {
(_, true) => DebugLevel::FULL,
(false, false) => DebugLevel::APP_ONLY,
@@ -97,15 +117,14 @@
(Some(console_fd), Some(log_fd))
};
- let config_path = parameters.config_path.as_deref().unwrap_or(DEFAULT_VM_CONFIG_PATH);
let config = VirtualMachineConfig::AppConfig(VirtualMachineAppConfig {
name: String::from("Compos"),
apk: Some(apk_fd),
idsig: Some(idsig_fd),
instanceImage: Some(instance_fd),
- configPath: config_path.to_owned(),
+ configPath: config_path,
debugLevel: debug_level,
- extraIdsigs: vec![idsig_manifest_apk_fd],
+ extraIdsigs: extra_idsigs,
protectedVm: protected_vm,
memoryMib: parameters.memory_mib.unwrap_or(0), // 0 means use the default
numCpus: parameters.cpus.map_or(1, NonZeroU32::get) as i32,
diff --git a/compos/common/lib.rs b/compos/common/lib.rs
index a5b1ea8..c9555d5 100644
--- a/compos/common/lib.rs
+++ b/compos/common/lib.rs
@@ -48,16 +48,31 @@
/// The file that holds the idsig for the CompOS Payload APK.
pub const IDSIG_FILE: &str = "idsig";
-/// The file that holds the idsig for the build manifest APK (that makes enumerated files from
-/// /system available in CompOS).
+/// The file that holds the idsig for the build manifest APK that makes enumerated files from
+/// /system available in CompOS.
pub const IDSIG_MANIFEST_APK_FILE: &str = "idsig_manifest_apk";
-/// The path within our config APK of our default VM configuration file, used at boot time.
-pub const DEFAULT_VM_CONFIG_PATH: &str = "assets/vm_config.json";
-
-/// The path within our config APK of the VM configuration file we use when compiling staged
-/// APEXes before reboot.
-pub const PREFER_STAGED_VM_CONFIG_PATH: &str = "assets/vm_config_staged.json";
+/// The file that holds the idsig for the build manifest APK that makes enumerated files from
+/// /system_ext available in CompOS.
+pub const IDSIG_MANIFEST_EXT_APK_FILE: &str = "idsig_manifest_ext_apk";
/// Number of CPUs to run dex2oat (actually the entire compos VM) with
pub const DEX2OAT_THREADS_PROP_NAME: &str = "dalvik.vm.boot-dex2oat-threads";
+
+/// The Android path of fs-verity build manifest APK for /system.
+pub const BUILD_MANIFEST_APK_PATH: &str = "/system/etc/security/fsverity/BuildManifest.apk";
+
+/// The Android path of fs-verity build manifest APK for /system_ext.
+pub const BUILD_MANIFEST_SYSTEM_EXT_APK_PATH: &str =
+ "/system_ext/etc/security/fsverity/BuildManifestSystemExt.apk";
+
+/// Returns the path of proper VM config for the current device.
+pub fn get_vm_config_path(has_system_ext: bool, prefer_staged: bool) -> String {
+ match (has_system_ext, prefer_staged) {
+ (false, false) => "assets/vm_config.json",
+ (false, true) => "assets/vm_config_staged.json",
+ (true, false) => "assets/vm_config_system_ext.json",
+ (true, true) => "assets/vm_config_system_ext_staged.json",
+ }
+ .to_owned()
+}
diff --git a/compos/composd/src/instance_manager.rs b/compos/composd/src/instance_manager.rs
index 451222e..c3d6592 100644
--- a/compos/composd/src/instance_manager.rs
+++ b/compos/composd/src/instance_manager.rs
@@ -22,10 +22,7 @@
use anyhow::{bail, Result};
use binder::Strong;
use compos_common::compos_client::VmParameters;
-use compos_common::{
- CURRENT_INSTANCE_DIR, DEX2OAT_THREADS_PROP_NAME, PREFER_STAGED_VM_CONFIG_PATH,
- TEST_INSTANCE_DIR,
-};
+use compos_common::{CURRENT_INSTANCE_DIR, DEX2OAT_THREADS_PROP_NAME, TEST_INSTANCE_DIR};
use rustutils::system_properties;
use std::num::NonZeroU32;
use std::str::FromStr;
@@ -47,16 +44,14 @@
pub fn start_current_instance(&self) -> Result<CompOsInstance> {
let mut vm_parameters = new_vm_parameters()?;
- vm_parameters.config_path = Some(PREFER_STAGED_VM_CONFIG_PATH.to_owned());
+ vm_parameters.prefer_staged = true;
self.start_instance(CURRENT_INSTANCE_DIR, vm_parameters)
}
pub fn start_test_instance(&self, prefer_staged: bool) -> Result<CompOsInstance> {
let mut vm_parameters = new_vm_parameters()?;
vm_parameters.debug_mode = true;
- if prefer_staged {
- vm_parameters.config_path = Some(PREFER_STAGED_VM_CONFIG_PATH.to_owned());
- }
+ vm_parameters.prefer_staged = prefer_staged;
self.start_instance(TEST_INSTANCE_DIR, vm_parameters)
}
diff --git a/compos/composd/src/instance_starter.rs b/compos/composd/src/instance_starter.rs
index aaa4695..fc4c58b 100644
--- a/compos/composd/src/instance_starter.rs
+++ b/compos/composd/src/instance_starter.rs
@@ -24,7 +24,10 @@
use binder::{LazyServiceGuard, ParcelFileDescriptor, Strong};
use compos_aidl_interface::aidl::com::android::compos::ICompOsService::ICompOsService;
use compos_common::compos_client::{ComposClient, VmParameters};
-use compos_common::{COMPOS_DATA_ROOT, IDSIG_FILE, IDSIG_MANIFEST_APK_FILE, INSTANCE_IMAGE_FILE};
+use compos_common::{
+ COMPOS_DATA_ROOT, IDSIG_FILE, IDSIG_MANIFEST_APK_FILE, IDSIG_MANIFEST_EXT_APK_FILE,
+ INSTANCE_IMAGE_FILE,
+};
use log::info;
use std::fs;
use std::path::{Path, PathBuf};
@@ -66,6 +69,7 @@
instance_image: PathBuf,
idsig: PathBuf,
idsig_manifest_apk: PathBuf,
+ idsig_manifest_ext_apk: PathBuf,
vm_parameters: VmParameters,
}
@@ -76,12 +80,14 @@
let instance_image = instance_root_path.join(INSTANCE_IMAGE_FILE);
let idsig = instance_root_path.join(IDSIG_FILE);
let idsig_manifest_apk = instance_root_path.join(IDSIG_MANIFEST_APK_FILE);
+ let idsig_manifest_ext_apk = instance_root_path.join(IDSIG_MANIFEST_EXT_APK_FILE);
Self {
instance_name: instance_name.to_owned(),
instance_root,
instance_image,
idsig,
idsig_manifest_apk,
+ idsig_manifest_ext_apk,
vm_parameters,
}
}
@@ -102,6 +108,7 @@
// Delete existing idsig files. Ignore error in case idsig doesn't exist.
let _ = fs::remove_file(&self.idsig);
let _ = fs::remove_file(&self.idsig_manifest_apk);
+ let _ = fs::remove_file(&self.idsig_manifest_ext_apk);
let instance = self.start_vm(virtualization_service)?;
@@ -126,6 +133,7 @@
instance_image,
&self.idsig,
&self.idsig_manifest_apk,
+ &self.idsig_manifest_ext_apk,
&self.vm_parameters,
)
.context("Starting VM")?;
diff --git a/compos/composd/src/odrefresh_task.rs b/compos/composd/src/odrefresh_task.rs
index 5c926b1..a07a7f9 100644
--- a/compos/composd/src/odrefresh_task.rs
+++ b/compos/composd/src/odrefresh_task.rs
@@ -161,9 +161,18 @@
let output_dir_raw_fd = output_dir_fd.as_raw_fd();
let staging_dir_raw_fd = staging_dir_fd.as_raw_fd();
+ // Get the /system_ext FD differently because it may not exist.
+ // TODO(245761690): pass system_ext_dir_raw_fd to service.odrefresh(...)
+ let (_system_ext_dir_raw_fd, ro_dir_fds) =
+ if let Ok(system_ext_dir_fd) = open_dir(Path::new("/system_ext")) {
+ (system_ext_dir_fd.as_raw_fd(), vec![system_dir_fd, system_ext_dir_fd])
+ } else {
+ (-1, vec![system_dir_fd])
+ };
+
// Spawn a fd_server to serve the FDs.
let fd_server_config = FdServerConfig {
- ro_dir_fds: vec![system_dir_fd],
+ ro_dir_fds,
rw_dir_fds: vec![staging_dir_fd, output_dir_fd],
..Default::default()
};
diff --git a/compos/verify/verify.rs b/compos/verify/verify.rs
index 3abdc74..5b7a8ad 100644
--- a/compos/verify/verify.rs
+++ b/compos/verify/verify.rs
@@ -28,7 +28,7 @@
};
use compos_common::{
COMPOS_DATA_ROOT, CURRENT_INSTANCE_DIR, IDSIG_FILE, IDSIG_MANIFEST_APK_FILE,
- INSTANCE_IMAGE_FILE, TEST_INSTANCE_DIR,
+ IDSIG_MANIFEST_EXT_APK_FILE, INSTANCE_IMAGE_FILE, TEST_INSTANCE_DIR,
};
use log::error;
use std::fs::File;
@@ -93,6 +93,7 @@
let instance_image = instance_dir.join(INSTANCE_IMAGE_FILE);
let idsig = instance_dir.join(IDSIG_FILE);
let idsig_manifest_apk = instance_dir.join(IDSIG_MANIFEST_APK_FILE);
+ let idsig_manifest_ext_apk = instance_dir.join(IDSIG_MANIFEST_EXT_APK_FILE);
let instance_image = File::open(instance_image).context("Failed to open instance image")?;
@@ -111,6 +112,7 @@
instance_image,
&idsig,
&idsig_manifest_apk,
+ &idsig_manifest_ext_apk,
&VmParameters { debug_mode: args.debug, ..Default::default() },
)?;