Don't start composd if VMs are not supported
If we attempt to it will abort (because virtmgr will abort), and
service manager will keep trying to sstart it forever.
To avoid having a third copy of the hypervisor properties code,
extract it to a library.
Fix "vm info" so it works even in the absence of VM support, by not
connecting to virtmgr when we don't need to.
Also remove duplication from the composd_cmd build file, to make it
harder to accidentally break the test build.
Bug: 254599807
Test: "vm info", "vm list", "composd test-compile" with & without
VM enabled
Test: atest composd_cmd.test
Change-Id: I1f33e231fcf9c77ce16a6b2cfb51d67da3986a6d
diff --git a/compos/composd_cmd/Android.bp b/compos/composd_cmd/Android.bp
index 54b0bad..77caad8 100644
--- a/compos/composd_cmd/Android.bp
+++ b/compos/composd_cmd/Android.bp
@@ -2,8 +2,8 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-rust_binary {
- name: "composd_cmd",
+rust_defaults {
+ name: "composd_cmd_defaults",
srcs: ["composd_cmd.rs"],
edition: "2021",
rustlibs: [
@@ -12,8 +12,14 @@
"libbinder_rs",
"libclap",
"libcompos_common",
+ "libhypervisor_props",
],
prefer_rlib: true,
+}
+
+rust_binary {
+ name: "composd_cmd",
+ defaults: ["composd_cmd_defaults"],
apex_available: [
"com.android.compos",
],
@@ -21,15 +27,6 @@
rust_test {
name: "composd_cmd.test",
- srcs: ["composd_cmd.rs"],
- edition: "2021",
- rustlibs: [
- "android.system.composd-rust",
- "libanyhow",
- "libbinder_rs",
- "libclap",
- "libcompos_common",
- ],
- prefer_rlib: true,
+ defaults: ["composd_cmd_defaults"],
test_suites: ["general-tests"],
}
diff --git a/compos/composd_cmd/composd_cmd.rs b/compos/composd_cmd/composd_cmd.rs
index 19c3720..6d096a1 100644
--- a/compos/composd_cmd/composd_cmd.rs
+++ b/compos/composd_cmd/composd_cmd.rs
@@ -128,6 +128,12 @@
&Strong<dyn ICompilationTaskCallback>,
) -> BinderResult<Strong<dyn ICompilationTask>>,
{
+ if !hypervisor_props::is_any_vm_supported()? {
+ // Give up now, before trying to start composd, or we may end up waiting forever
+ // as it repeatedly starts and then aborts (b/254599807).
+ bail!("Device doesn't support protected or non-protected VMs")
+ }
+
let service = wait_for_interface::<dyn IIsolatedCompilationService>("android.system.composd")
.context("Failed to connect to composd service")?;
diff --git a/libs/hypervisor_props/Android.bp b/libs/hypervisor_props/Android.bp
new file mode 100644
index 0000000..af08b01
--- /dev/null
+++ b/libs/hypervisor_props/Android.bp
@@ -0,0 +1,18 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_library {
+ name: "libhypervisor_props",
+ crate_name: "hypervisor_props",
+ srcs: ["src/lib.rs"],
+ edition: "2021",
+ rustlibs: [
+ "libanyhow",
+ "librustutils",
+ ],
+ apex_available: [
+ "com.android.compos",
+ "com.android.virt",
+ ],
+}
diff --git a/libs/hypervisor_props/src/lib.rs b/libs/hypervisor_props/src/lib.rs
new file mode 100644
index 0000000..120a48c
--- /dev/null
+++ b/libs/hypervisor_props/src/lib.rs
@@ -0,0 +1,40 @@
+// Copyright 2023, 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.
+
+//! Access to hypervisor capabilities via system properties set by the bootloader.
+
+use anyhow::{Error, Result};
+use rustutils::system_properties;
+
+/// Returns whether there is a hypervisor present that supports non-protected VMs.
+pub fn is_vm_supported() -> Result<bool> {
+ system_properties::read_bool("ro.boot.hypervisor.vm.supported", false).map_err(Error::new)
+}
+
+/// Returns whether there is a hypervisor present that supports protected VMs.
+pub fn is_protected_vm_supported() -> Result<bool> {
+ system_properties::read_bool("ro.boot.hypervisor.protected_vm.supported", false)
+ .map_err(Error::new)
+}
+
+/// Returns whether there is a hypervisor present that supports any sort of VM, either protected
+/// or non-protected.
+pub fn is_any_vm_supported() -> Result<bool> {
+ is_vm_supported().and_then(|ok| if ok { Ok(true) } else { is_protected_vm_supported() })
+}
+
+/// Returns the version of the hypervisor, if there is one.
+pub fn version() -> Result<Option<String>> {
+ system_properties::read("ro.boot.hypervisor.version").map_err(Error::new)
+}
diff --git a/virtualizationmanager/Android.bp b/virtualizationmanager/Android.bp
index a436cea..e82797e 100644
--- a/virtualizationmanager/Android.bp
+++ b/virtualizationmanager/Android.bp
@@ -32,6 +32,7 @@
"libclap",
"libcommand_fds",
"libdisk",
+ "libhypervisor_props",
"liblazy_static",
"liblibc",
"liblog_rust",
diff --git a/virtualizationmanager/src/main.rs b/virtualizationmanager/src/main.rs
index dca64cb..3f0b64b 100644
--- a/virtualizationmanager/src/main.rs
+++ b/virtualizationmanager/src/main.rs
@@ -23,7 +23,7 @@
use crate::aidl::{GLOBAL_SERVICE, VirtualizationService};
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualizationService::BnVirtualizationService;
-use anyhow::{bail, Context};
+use anyhow::{bail, Context, Result};
use binder::{BinderFeatures, ProcessState};
use lazy_static::lazy_static;
use log::{info, Level};
@@ -33,7 +33,6 @@
use nix::fcntl::{fcntl, F_GETFD, F_SETFD, FdFlag};
use nix::unistd::{Pid, Uid};
use std::os::unix::raw::{pid_t, uid_t};
-use rustutils::system_properties;
const LOG_TAG: &str = "virtmgr";
@@ -92,9 +91,15 @@
Ok(unsafe { OwnedFd::from_raw_fd(raw_fd) })
}
-fn is_property_set(name: &str) -> bool {
- system_properties::read_bool(name, false)
- .unwrap_or_else(|e| panic!("Failed to read {name}: {e:?}"))
+fn check_vm_support() -> Result<()> {
+ if hypervisor_props::is_any_vm_supported()? {
+ Ok(())
+ } else {
+ // This should never happen, it indicates a misconfigured device where the virt APEX
+ // is present but VMs are not supported. If it does happen, fail fast to avoid wasting
+ // resources trying.
+ bail!("Device doesn't support protected or non-protected VMs")
+ }
}
fn main() {
@@ -105,14 +110,7 @@
.with_log_id(android_logger::LogId::System),
);
- let non_protected_vm_supported = is_property_set("ro.boot.hypervisor.vm.supported");
- let protected_vm_supported = is_property_set("ro.boot.hypervisor.protected_vm.supported");
- if !non_protected_vm_supported && !protected_vm_supported {
- // This should never happen, it indicates a misconfigured device where the virt APEX
- // is present but VMs are not supported. If it does happen, fail fast to avoid wasting
- // resources trying.
- panic!("Device doesn't support protected or unprotected VMs");
- }
+ check_vm_support().unwrap();
let args = Args::parse();
diff --git a/vm/Android.bp b/vm/Android.bp
index e217786..50e68cc 100644
--- a/vm/Android.bp
+++ b/vm/Android.bp
@@ -15,11 +15,11 @@
"libclap",
"libenv_logger",
"libglob",
+ "libhypervisor_props",
"liblibc",
"liblog_rust",
"libmicrodroid_payload_config",
"librand",
- "librustutils",
"libserde_json",
"libserde",
"libvmconfig",
diff --git a/vm/src/main.rs b/vm/src/main.rs
index e1c3413..6c08a19 100644
--- a/vm/src/main.rs
+++ b/vm/src/main.rs
@@ -23,12 +23,11 @@
PartitionType::PartitionType, VirtualMachineAppConfig::DebugLevel::DebugLevel,
};
use anyhow::{Context, Error};
-use binder::ProcessState;
+use binder::{ProcessState, Strong};
use clap::Parser;
use create_idsig::command_create_idsig;
use create_partition::command_create_partition;
use run::{command_run, command_run_app, command_run_microdroid};
-use rustutils::system_properties;
use std::path::{Path, PathBuf};
#[derive(Debug)]
@@ -230,6 +229,12 @@
}
}
+fn get_service() -> Result<Strong<dyn IVirtualizationService>, Error> {
+ let virtmgr =
+ vmclient::VirtualizationService::new().context("Failed to spawn VirtualizationService")?;
+ virtmgr.connect().context("Failed to connect to VirtualizationService")
+}
+
fn main() -> Result<(), Error> {
env_logger::init();
let opt = Opt::parse();
@@ -237,10 +242,6 @@
// We need to start the thread pool for Binder to work properly, especially link_to_death.
ProcessState::start_thread_pool();
- let virtmgr =
- vmclient::VirtualizationService::new().context("Failed to spawn VirtualizationService")?;
- let service = virtmgr.connect().context("Failed to connect to VirtualizationService")?;
-
match opt {
Opt::RunApp {
name,
@@ -261,7 +262,7 @@
extra_idsigs,
} => command_run_app(
name,
- service.as_ref(),
+ get_service()?.as_ref(),
&apk,
&idsig,
&instance,
@@ -292,7 +293,7 @@
task_profiles,
} => command_run_microdroid(
name,
- service.as_ref(),
+ get_service()?.as_ref(),
work_dir,
storage.as_deref(),
storage_size,
@@ -307,7 +308,7 @@
Opt::Run { name, config, cpu_topology, task_profiles, console, log } => {
command_run(
name,
- service.as_ref(),
+ get_service()?.as_ref(),
&config,
console.as_deref(),
log.as_deref(),
@@ -316,12 +317,14 @@
task_profiles,
)
}
- Opt::List => command_list(service.as_ref()),
+ Opt::List => command_list(get_service()?.as_ref()),
Opt::Info => command_info(),
Opt::CreatePartition { path, size, partition_type } => {
- command_create_partition(service.as_ref(), &path, size, partition_type)
+ command_create_partition(get_service()?.as_ref(), &path, size, partition_type)
}
- Opt::CreateIdsig { apk, path } => command_create_idsig(service.as_ref(), &apk, &path),
+ Opt::CreateIdsig { apk, path } => {
+ command_create_idsig(get_service()?.as_ref(), &apk, &path)
+ }
}
}
@@ -334,10 +337,8 @@
/// Print information about supported VM types.
fn command_info() -> Result<(), Error> {
- let non_protected_vm_supported =
- system_properties::read_bool("ro.boot.hypervisor.vm.supported", false)?;
- let protected_vm_supported =
- system_properties::read_bool("ro.boot.hypervisor.protected_vm.supported", false)?;
+ let non_protected_vm_supported = hypervisor_props::is_vm_supported()?;
+ let protected_vm_supported = hypervisor_props::is_protected_vm_supported()?;
match (non_protected_vm_supported, protected_vm_supported) {
(false, false) => println!("VMs are not supported."),
(false, true) => println!("Only protected VMs are supported."),
@@ -345,7 +346,7 @@
(true, true) => println!("Both protected and non-protected VMs are supported."),
}
- if let Some(version) = system_properties::read("ro.boot.hypervisor.version")? {
+ if let Some(version) = hypervisor_props::version()? {
println!("Hypervisor version: {}", version);
} else {
println!("Hypervisor version not set.");