Merge "Allocate swiotlb buffer size based on number of virtio devices."
diff --git a/compos/common/compos_client.rs b/compos/common/compos_client.rs
index 72d2b76..69f095a 100644
--- a/compos/common/compos_client.rs
+++ b/compos/common/compos_client.rs
@@ -200,21 +200,20 @@
 
 fn want_protected_vm() -> Result<bool> {
     let have_protected_vm =
-        system_properties::read_bool("ro.boot.hypervisor.protected_vm.supported", false)
-            .unwrap_or(false);
+        system_properties::read_bool("ro.boot.hypervisor.protected_vm.supported", false)?;
     if have_protected_vm {
         info!("Starting protected VM");
         return Ok(true);
     }
 
-    let build_type = system_properties::read("ro.build.type")?;
+    let build_type = system_properties::read("ro.build.type")?.context("ro.build.type not set")?;
     let is_debug_build = matches!(build_type.as_str(), "userdebug" | "eng");
     if !is_debug_build {
         bail!("Protected VM not supported, unable to start VM");
     }
 
     let have_unprotected_vm =
-        system_properties::read_bool("ro.boot.hypervisor.vm.supported", false).unwrap_or(false);
+        system_properties::read_bool("ro.boot.hypervisor.vm.supported", false)?;
     if have_unprotected_vm {
         warn!("Protected VM not supported, falling back to unprotected on {} build", build_type);
         return Ok(false);
diff --git a/compos/common/timeouts.rs b/compos/common/timeouts.rs
index c86ae34..e6cc430 100644
--- a/compos/common/timeouts.rs
+++ b/compos/common/timeouts.rs
@@ -35,8 +35,11 @@
 /// Whether the current platform requires extra time for operations inside a VM.
 pub fn need_extra_time() -> Result<bool> {
     // Nested virtualization is slow. Check if we are running on vsoc as a proxy for this.
-    let value = system_properties::read("ro.build.product")?;
-    Ok(value == "vsoc_x86_64" || value == "vsoc_x86")
+    if let Some(value) = system_properties::read("ro.build.product")? {
+        Ok(value == "vsoc_x86_64" || value == "vsoc_x86")
+    } else {
+        Ok(false)
+    }
 }
 
 /// Return the timeouts that are appropriate on the current platform.
diff --git a/compos/composd/src/instance_manager.rs b/compos/composd/src/instance_manager.rs
index 2f15cb5..9761a3e 100644
--- a/compos/composd/src/instance_manager.rs
+++ b/compos/composd/src/instance_manager.rs
@@ -83,15 +83,15 @@
 }
 
 fn new_vm_parameters() -> Result<VmParameters> {
-    let cpus = match system_properties::read(DEX2OAT_THREADS_PROP_NAME) {
-        Ok(s) => Some(NonZeroU32::from_str(&s)?),
-        Err(_) => {
+    let cpus = match system_properties::read(DEX2OAT_THREADS_PROP_NAME)? {
+        Some(s) => Some(NonZeroU32::from_str(&s)?),
+        None => {
             // dex2oat uses all CPUs by default. To match the behavior, give the VM all CPUs by
             // default.
             NonZeroU32::new(num_cpus::get() as u32)
         }
     };
-    let cpu_set = system_properties::read(DEX2OAT_CPU_SET_PROP_NAME).ok();
+    let cpu_set = system_properties::read(DEX2OAT_CPU_SET_PROP_NAME)?;
     Ok(VmParameters { cpus, cpu_set, ..Default::default() })
 }
 
diff --git a/compos/composd/src/odrefresh_task.rs b/compos/composd/src/odrefresh_task.rs
index 82eedc4..d1d0e28 100644
--- a/compos/composd/src/odrefresh_task.rs
+++ b/compos/composd/src/odrefresh_task.rs
@@ -145,9 +145,9 @@
     };
     let fd_server_raii = fd_server_config.into_fd_server()?;
 
-    let zygote_arch = system_properties::read("ro.zygote")?;
+    let zygote_arch = system_properties::read("ro.zygote")?.context("ro.zygote not set")?;
     let system_server_compiler_filter =
-        system_properties::read("dalvik.vm.systemservercompilerfilter").unwrap_or_default();
+        system_properties::read("dalvik.vm.systemservercompilerfilter")?.unwrap_or_default();
     let exit_code = service.odrefresh(
         compilation_mode,
         system_dir.as_raw_fd(),
diff --git a/microdroid/Android.bp b/microdroid/Android.bp
index 7384cef..a93a801 100644
--- a/microdroid/Android.bp
+++ b/microdroid/Android.bp
@@ -292,18 +292,24 @@
     avb_private_key: ":microdroid_sign_key",
 }
 
-android_filesystem {
-    name: "microdroid_vendor_ramdisk-5.10",
+prebuilt_kernel_modules {
+    name: "microdroid_kernel_modules",
     arch: {
         arm64: {
-            deps: ["virt_device_prebuilts_kernel_modules-5.10-arm64"],
+            srcs: [":virt_device_prebuilts_kernel_modules_microdroid-5.10-arm64"],
         },
         x86_64: {
-            deps: ["virt_device_prebuilts_kernel_modules-5.10-x86_64"],
+            srcs: [":virt_device_prebuilts_kernel_modules_microdroid-5.10-x86_64"],
         },
     },
+    kernel_version: "5.10",
+}
+
+android_filesystem {
+    name: "microdroid_vendor_ramdisk-5.10",
     deps: [
         "microdroid_fstab",
+        "microdroid_kernel_modules",
     ],
     base_dir: "first_stage_ramdisk",
     type: "compressed_cpio",
diff --git a/tests/Android.bp b/tests/Android.bp
index 58cc06f..74d58f5 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -19,7 +19,6 @@
 kernel_version = "5.10"
 
 kernel_stem = "kernel_prebuilts-" + kernel_version
-kernel_modules_stem = "virt_device_prebuilts_kernel_modules-" + kernel_version
 
 cc_test {
     // ".64" suffix is to work around cts-unit-test which is demanding that all
@@ -85,15 +84,8 @@
 
 android_filesystem {
     name: "virt_test_initramfs",
-    arch: {
-        arm64: {
-            deps: [kernel_modules_stem + "-arm64"],
-        },
-        x86_64: {
-            deps: [kernel_modules_stem + "-x86_64"],
-        },
-    },
     deps: [
+        "microdroid_kernel_modules",
         "virt_test_guest_init",
         "virt_test_vsock_guest",
     ],
diff --git a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
index 8cfb3a1..061e8cf 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -30,6 +30,7 @@
 import android.os.Build;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
+import android.os.SystemProperties;
 import android.system.virtualmachine.VirtualMachine;
 import android.system.virtualmachine.VirtualMachineCallback;
 import android.system.virtualmachine.VirtualMachineConfig;
@@ -62,6 +63,8 @@
 public class MicrodroidTests {
     @Rule public Timeout globalTimeout = Timeout.seconds(300);
 
+    private static final String KERNEL_VERSION = SystemProperties.get("ro.kernel.version");
+
     private static class Inner {
         public Context mContext;
         public VirtualMachineManager mVmm;
@@ -140,6 +143,11 @@
 
     @Test
     public void connectToVmService() throws VirtualMachineException, InterruptedException {
+        assume()
+            .withMessage("SKip on 5.4 kernel. b/218303240")
+            .that(KERNEL_VERSION)
+            .isNotEqualTo("5.4");
+
         VirtualMachineConfig.Builder builder =
                 new VirtualMachineConfig.Builder(mInner.mContext,
                         "assets/vm_config_extra_apk.json");
@@ -218,6 +226,11 @@
             .that(android.os.Build.DEVICE)
             .isNotEqualTo("vsoc_x86_64");
 
+        assume()
+            .withMessage("SKip on 5.4 kernel. b/218303240")
+            .that(KERNEL_VERSION)
+            .isNotEqualTo("5.4");
+
         VirtualMachineConfig.Builder builder =
                 new VirtualMachineConfig.Builder(mInner.mContext, "assets/vm_config.json");
         VirtualMachineConfig normalConfig = builder.debugLevel(DebugLevel.NONE).build();
@@ -301,6 +314,11 @@
             .that(android.os.Build.DEVICE)
             .isNotEqualTo("vsoc_x86_64");
 
+        assume()
+            .withMessage("SKip on 5.4 kernel. b/218303240")
+            .that(KERNEL_VERSION)
+            .isNotEqualTo("5.4");
+
         byte[] vm_a_secret = launchVmAndGetSecret("test_vm_a");
         byte[] vm_b_secret = launchVmAndGetSecret("test_vm_b");
         assertThat(vm_a_secret).isNotNull();
@@ -316,6 +334,11 @@
             .that(android.os.Build.DEVICE)
             .isNotEqualTo("vsoc_x86_64");
 
+        assume()
+            .withMessage("SKip on 5.4 kernel. b/218303240")
+            .that(KERNEL_VERSION)
+            .isNotEqualTo("5.4");
+
         byte[] vm_secret_first_boot = launchVmAndGetSecret("test_vm");
         byte[] vm_secret_second_boot = launchVmAndGetSecret("test_vm");
         assertThat(vm_secret_first_boot).isNotNull();
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index ebb01b3..7e0c634 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -868,7 +868,7 @@
 /// a system property so that restart of virtualizationservice doesn't reuse CID while the host
 /// Android is up.
 fn next_cid() -> Result<Cid> {
-    let next = if let Ok(val) = system_properties::read(SYSPROP_LAST_CID) {
+    let next = if let Some(val) = system_properties::read(SYSPROP_LAST_CID)? {
         if let Ok(num) = val.parse::<u32>() {
             num.checked_add(1).ok_or_else(|| anyhow!("run out of CID"))?
         } else {
diff --git a/vm/Android.bp b/vm/Android.bp
index 2d22562..d1d53d0 100644
--- a/vm/Android.bp
+++ b/vm/Android.bp
@@ -15,6 +15,7 @@
         "liblibc",
         "liblog_rust",
         "libmicrodroid_payload_config",
+        "librustutils",
         "libserde_json",
         "libserde",
         "libstructopt",
diff --git a/vm/src/main.rs b/vm/src/main.rs
index 25f9bfb..2cbae3e 100644
--- a/vm/src/main.rs
+++ b/vm/src/main.rs
@@ -26,7 +26,8 @@
 use anyhow::{Context, Error};
 use create_partition::command_create_partition;
 use run::{command_run, command_run_app};
-use std::path::PathBuf;
+use rustutils::system_properties;
+use std::path::{Path, PathBuf};
 use structopt::clap::AppSettings;
 use structopt::StructOpt;
 
@@ -126,6 +127,8 @@
     },
     /// List running virtual machines
     List,
+    /// Print information about virtual machine support
+    Info,
     /// Create a new empty partition to be used as a writable partition for a VM
     CreatePartition {
         /// Path at which to create the image file
@@ -212,6 +215,7 @@
         }
         Opt::Stop { cid } => command_stop(service, cid),
         Opt::List => command_list(service),
+        Opt::Info => command_info(),
         Opt::CreatePartition { path, size, partition_type } => {
             command_create_partition(service, &path, size, partition_type)
         }
@@ -233,3 +237,31 @@
     println!("Running VMs: {:#?}", vms);
     Ok(())
 }
+
+/// Print information about supported VM types.
+fn command_info() -> Result<(), Error> {
+    let unprotected_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)?;
+    match (unprotected_vm_supported, protected_vm_supported) {
+        (false, false) => println!("VMs are not supported."),
+        (false, true) => println!("Only protected VMs are supported."),
+        (true, false) => println!("Only unprotected VMs are supported."),
+        (true, true) => println!("Both protected and unprotected VMs are supported."),
+    }
+
+    if let Some(version) = system_properties::read("ro.boot.hypervisor.version")? {
+        println!("Hypervisor version: {}", version);
+    } else {
+        println!("Hypervisor version not set.");
+    }
+
+    if Path::new("/dev/kvm").exists() {
+        println!("/dev/kvm exists.");
+    } else {
+        println!("/dev/kvm does not exist.");
+    }
+
+    Ok(())
+}