Merge "Only run MicrodroidTestApp.GTS on devices with SDK >= 34" into main
diff --git a/OWNERS b/OWNERS
index af71ad6..71d2680 100644
--- a/OWNERS
+++ b/OWNERS
@@ -9,8 +9,8 @@
 willdeacon@google.com
 
 # Other owners
-alanstokes@google.com
 aliceywang@google.com
+fmayle@google.com
 inseob@google.com
 ioffe@google.com
 jaewan@google.com
diff --git a/android/TerminalApp/proguard.flags b/android/TerminalApp/proguard.flags
index 04a2140..e0c49f5 100644
--- a/android/TerminalApp/proguard.flags
+++ b/android/TerminalApp/proguard.flags
@@ -19,10 +19,22 @@
 
 # Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
 # JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
--keep class * extends com.google.gson.TypeAdapter
--keep class * implements com.google.gson.TypeAdapterFactory
--keep class * implements com.google.gson.JsonSerializer
--keep class * implements com.google.gson.JsonDeserializer
+# TODO(b/373579455): Evaluate if <init> needs to be kept.
+-keep class * extends com.google.gson.TypeAdapter {
+  void <init>();
+}
+# TODO(b/373579455): Evaluate if <init> needs to be kept.
+-keep class * implements com.google.gson.TypeAdapterFactory {
+  void <init>();
+}
+# TODO(b/373579455): Evaluate if <init> needs to be kept.
+-keep class * implements com.google.gson.JsonSerializer {
+  void <init>();
+}
+# TODO(b/373579455): Evaluate if <init> needs to be kept.
+-keep class * implements com.google.gson.JsonDeserializer {
+  void <init>();
+}
 
 # Prevent R8 from leaving Data object members always null
 -keepclassmembers,allowobfuscation class * {
@@ -30,7 +42,13 @@
 }
 
 # Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
--keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
--keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
+# TODO(b/373579455): Evaluate if <init> needs to be kept.
+-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken {
+  void <init>();
+}
+# TODO(b/373579455): Evaluate if <init> needs to be kept.
+-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken {
+  void <init>();
+}
 
 ##---------------End: proguard configuration for Gson  ----------
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index 2d31b87..9ba1c04 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -31,7 +31,6 @@
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
     AssignedDevices::AssignedDevices,
     AssignableDevice::AssignableDevice,
-    CpuTopology::CpuTopology,
     DiskImage::DiskImage,
     SharedPath::SharedPath,
     InputDevice::InputDevice,
@@ -712,24 +711,6 @@
 
         let shared_paths = assemble_shared_paths(&config.sharedPaths, &temporary_directory)?;
 
-        let (cpus, host_cpu_topology) = match config.cpuTopology {
-            CpuTopology::MATCH_HOST => (None, true),
-            CpuTopology::ONE_CPU => (NonZeroU32::new(1), false),
-            CpuTopology::CUSTOM => (
-                NonZeroU32::new(
-                    u32::try_from(config.customVcpuCount)
-                        .context("bad customVcpuCount")
-                        .or_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT)?,
-                ),
-                false,
-            ),
-            val => {
-                return Err(anyhow!("Failed to parse CPU topology value {:?}", val))
-                    .with_log()
-                    .or_service_specific_exception(-1);
-            }
-        };
-
         let (vfio_devices, dtbo) = match &config.devices {
             AssignedDevices::Devices(devices) if !devices.is_empty() => {
                 let mut set = HashSet::new();
@@ -840,8 +821,7 @@
                 .and_then(NonZeroU32::new)
                 .unwrap_or(NonZeroU32::new(256).unwrap()),
             swiotlb_mib: config.swiotlbMib.try_into().ok().and_then(NonZeroU32::new),
-            cpus,
-            host_cpu_topology,
+            cpus: config.cpuOptions.clone(),
             console_out_fd,
             console_in_fd,
             log_fd,
@@ -1299,23 +1279,13 @@
         vm_config.teeServices.clone_from(&custom_config.teeServices);
     }
 
-    // Unfortunately specifying page_shift = 14 in bootconfig doesn't enable 16k pages emulation,
-    // so we need to provide it in the kernel cmdline.
-    // TODO(b/376901009): remove this after passing page_shift in bootconfig is supported.
-    if os_name.ends_with("_16k") && cfg!(target_arch = "x86_64") {
-        append_kernel_param("page_shift=14", &mut vm_config);
-    }
-
     if config.memoryMib > 0 {
         vm_config.memoryMib = config.memoryMib;
     }
 
     vm_config.name.clone_from(&config.name);
     vm_config.protectedVm = config.protectedVm;
-    vm_config.cpuTopology = config.cpuTopology;
-    if config.cpuTopology == CpuTopology::CUSTOM {
-        bail!("AppConfig doesn't support CpuTopology::CUSTOM");
-    }
+    vm_config.cpuOptions = config.cpuOptions.clone();
     vm_config.hugePages = config.hugePages || vm_payload_config.hugepages;
     vm_config.boostUclamp = config.boostUclamp;
 
diff --git a/android/virtmgr/src/atom.rs b/android/virtmgr/src/atom.rs
index e0fed85..33299aa 100644
--- a/android/virtmgr/src/atom.rs
+++ b/android/virtmgr/src/atom.rs
@@ -19,7 +19,8 @@
 use crate::get_calling_uid;
 use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::DeathReason::DeathReason;
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
-    CpuTopology::CpuTopology,
+    CpuOptions::CpuOptions,
+    CpuOptions::CpuTopology::CpuTopology,
     IVirtualMachine::IVirtualMachine,
     VirtualMachineAppConfig::{Payload::Payload, VirtualMachineAppConfig},
     VirtualMachineConfig::VirtualMachineConfig,
@@ -92,23 +93,15 @@
     }
 }
 
-fn get_num_vcpus(cpu_topology: CpuTopology, custom_vcpu_count: Option<i32>) -> i32 {
-    match cpu_topology {
-        CpuTopology::ONE_CPU => 1,
-        CpuTopology::MATCH_HOST => {
+fn get_num_vcpus(cpu_options: &CpuOptions) -> i32 {
+    match cpu_options.cpuTopology {
+        CpuTopology::MatchHost(_) => {
             get_num_cpus().and_then(|v| v.try_into().ok()).unwrap_or_else(|| {
                 warn!("Failed to determine the number of CPUs in the host");
                 INVALID_NUM_CPUS
             })
         }
-        CpuTopology::CUSTOM => custom_vcpu_count.unwrap_or_else(|| {
-            warn!("AppConfig doesn't support CpuTopology::CUSTOM");
-            INVALID_NUM_CPUS
-        }),
-        _ => {
-            warn!("invalid CpuTopology: {cpu_topology:?}");
-            INVALID_NUM_CPUS
-        }
+        CpuTopology::CpuCount(count) => count,
     }
 }
 
@@ -140,14 +133,14 @@
         VirtualMachineConfig::AppConfig(config) => (
             config.name.clone(),
             vm_creation_requested::ConfigType::VirtualMachineAppConfig,
-            get_num_vcpus(config.cpuTopology, None),
+            get_num_vcpus(&config.cpuOptions),
             config.memoryMib,
             get_apex_list(config),
         ),
         VirtualMachineConfig::RawConfig(config) => (
             config.name.clone(),
             vm_creation_requested::ConfigType::VirtualMachineRawConfig,
-            get_num_vcpus(config.cpuTopology, Some(config.customVcpuCount)),
+            get_num_vcpus(&config.cpuOptions),
             config.memoryMib,
             String::new(),
         ),
diff --git a/android/virtmgr/src/crosvm.rs b/android/virtmgr/src/crosvm.rs
index 00858cb..bb7712e 100644
--- a/android/virtmgr/src/crosvm.rs
+++ b/android/virtmgr/src/crosvm.rs
@@ -47,6 +47,8 @@
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
     VirtualMachineAppConfig::DebugLevel::DebugLevel,
     AudioConfig::AudioConfig as AudioConfigParcelable,
+    CpuOptions::CpuOptions,
+    CpuOptions::CpuTopology::CpuTopology,
     DisplayConfig::DisplayConfig as DisplayConfigParcelable,
     GpuConfig::GpuConfig as GpuConfigParcelable,
     UsbConfig::UsbConfig as UsbConfigParcelable,
@@ -113,8 +115,7 @@
     pub debug_config: DebugConfig,
     pub memory_mib: NonZeroU32,
     pub swiotlb_mib: Option<NonZeroU32>,
-    pub cpus: Option<NonZeroU32>,
-    pub host_cpu_topology: bool,
+    pub cpus: CpuOptions,
     pub console_out_fd: Option<File>,
     pub console_in_fd: Option<File>,
     pub log_fd: Option<File>,
@@ -1109,30 +1110,31 @@
 
     command.arg("--mem").arg(memory_mib.to_string());
 
-    if let Some(cpus) = config.cpus {
+    fn cpu_arg_command(command: &mut Command, count: usize) {
         #[cfg(target_arch = "aarch64")]
-        command.arg("--cpus").arg(cpus.to_string() + ",sve=[auto=true]");
+        command.arg("--cpus").arg(count.to_string() + ",sve=[auto=true]");
         #[cfg(not(target_arch = "aarch64"))]
-        command.arg("--cpus").arg(cpus.to_string());
+        command.arg("--cpus").arg(count.to_string());
     }
-
-    if config.host_cpu_topology {
-        if cfg!(virt_cpufreq) && check_if_all_cpus_allowed()? {
-            command.arg("--host-cpu-topology");
-            cfg_if::cfg_if! {
-                if #[cfg(any(target_arch = "aarch64"))] {
+    match config.cpus.cpuTopology {
+        CpuTopology::MatchHost(_) => {
+            if cfg!(virt_cpufreq) && check_if_all_cpus_allowed()? {
+                command.arg("--host-cpu-topology");
+                #[cfg(target_arch = "aarch64")]
+                {
                     command.arg("--virt-cpufreq");
+                    command.arg("--cpus").arg("sve=[auto=true]");
                 }
+            } else {
+                cpu_arg_command(
+                    &mut command,
+                    get_num_cpus()
+                        .context("Could not determine the number of CPUs in the system")?,
+                )
             }
-            #[cfg(target_arch = "aarch64")]
-            command.arg("--cpus").arg("sve=[auto=true]");
-        } else if let Some(cpus) = get_num_cpus() {
-            #[cfg(target_arch = "aarch64")]
-            command.arg("--cpus").arg(cpus.to_string() + ",sve=[auto=true]");
-            #[cfg(not(target_arch = "aarch64"))]
-            command.arg("--cpus").arg(cpus.to_string());
-        } else {
-            bail!("Could not determine the number of CPUs in the system");
+        }
+        CpuTopology::CpuCount(count) => {
+            cpu_arg_command(&mut command, count.try_into().context("invalid cpu count")?)
         }
     }
 
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/CpuTopology.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/CpuOptions.aidl
similarity index 63%
rename from android/virtualizationservice/aidl/android/system/virtualizationservice/CpuTopology.aidl
rename to android/virtualizationservice/aidl/android/system/virtualizationservice/CpuOptions.aidl
index 31a33f4..ae5044f 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/CpuTopology.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/CpuOptions.aidl
@@ -15,13 +15,17 @@
  */
 package android.system.virtualizationservice;
 
-/** The vCPU topology that will be generated for the VM. */
-@Backing(type="byte")
-enum CpuTopology {
-    /** One vCPU */
-    ONE_CPU = 0,
-    /** Match physical CPU topology of the host. */
-    MATCH_HOST = 1,
-    /** Number of vCPUs specified in the config. */
-    CUSTOM = 2,
+/** CPU options that will be used for the VM's Vcpus. */
+@RustDerive(Clone=true)
+parcelable CpuOptions {
+    @RustDerive(Clone=true, PartialEq=true)
+    union CpuTopology {
+        /** Number of Vcpus to boot the VM with. */
+        int cpuCount = 1;
+
+        /** Match host number of Vcpus to boot the VM with. */
+        boolean matchHost;
+    }
+
+    CpuTopology cpuTopology;
 }
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
index 114a851..5193e21 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
@@ -15,7 +15,7 @@
  */
 package android.system.virtualizationservice;
 
-import android.system.virtualizationservice.CpuTopology;
+import android.system.virtualizationservice.CpuOptions;
 import android.system.virtualizationservice.VirtualMachinePayloadConfig;
 
 /** Configuration for running an App in a VM */
@@ -93,8 +93,8 @@
      */
     int memoryMib;
 
-    /** The vCPU topology that will be generated for the VM. Default to 1 vCPU. */
-    CpuTopology cpuTopology = CpuTopology.ONE_CPU;
+    /** The vCPU options that will be generated for the VM. */
+    CpuOptions cpuOptions;
 
     /**
      * Encapsulates parameters that require android.permission.USE_CUSTOM_VIRTUAL_MACHINE.
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
index b6eff64..a822423 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
@@ -17,7 +17,7 @@
 
 import android.system.virtualizationservice.AssignedDevices;
 import android.system.virtualizationservice.AudioConfig;
-import android.system.virtualizationservice.CpuTopology;
+import android.system.virtualizationservice.CpuOptions;
 import android.system.virtualizationservice.DiskImage;
 import android.system.virtualizationservice.DisplayConfig;
 import android.system.virtualizationservice.GpuConfig;
@@ -66,11 +66,8 @@
     /** The amount of swiotlb to give the VM, in MiB. 0 or negative to use the default. */
     int swiotlbMib;
 
-    /** The vCPU topology that will be generated for the VM. Default to 1 vCPU. */
-    CpuTopology cpuTopology = CpuTopology.ONE_CPU;
-
-    /** The number of vCPUs. Ignored unless `cpuTopology == CUSTOM`. */
-    int customVcpuCount;
+    /** The vCPU options that will be generated for the VM. */
+    CpuOptions cpuOptions;
 
     /**
      * A version or range of versions of the virtual platform that this config is compatible with.
diff --git a/android/vm/src/main.rs b/android/vm/src/main.rs
index 830d56c..ff846a1 100644
--- a/android/vm/src/main.rs
+++ b/android/vm/src/main.rs
@@ -19,7 +19,7 @@
 mod run;
 
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
-    CpuTopology::CpuTopology, IVirtualizationService::IVirtualizationService,
+    CpuOptions::CpuTopology::CpuTopology, IVirtualizationService::IVirtualizationService,
     PartitionType::PartitionType, VirtualMachineAppConfig::DebugLevel::DebugLevel,
 };
 #[cfg(not(llpvm_changes))]
@@ -379,8 +379,13 @@
 
 fn parse_cpu_topology(s: &str) -> Result<CpuTopology, String> {
     match s {
-        "one_cpu" => Ok(CpuTopology::ONE_CPU),
-        "match_host" => Ok(CpuTopology::MATCH_HOST),
+        "one_cpu" => Ok(CpuTopology::CpuCount(1)),
+        "match_host" => Ok(CpuTopology::MatchHost(true)),
+        _ if s.starts_with("cpu_count=") => {
+            // Safe to unwrap as it's validated the string starts with cpu_count=
+            let val = s.strip_prefix("cpu_count=").unwrap();
+            Ok(CpuTopology::CpuCount(val.parse().map_err(|e| format!("Invalid CPU Count: {}", e))?))
+        }
         _ => Err(format!("Invalid cpu topology {}", s)),
     }
 }
diff --git a/android/vm/src/run.rs b/android/vm/src/run.rs
index 0037327..eaf2522 100644
--- a/android/vm/src/run.rs
+++ b/android/vm/src/run.rs
@@ -17,6 +17,7 @@
 use crate::create_partition::command_create_partition;
 use crate::{get_service, RunAppConfig, RunCustomVmConfig, RunMicrodroidConfig};
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
+    CpuOptions::CpuOptions,
     IVirtualizationService::IVirtualizationService,
     PartitionType::PartitionType,
     VirtualMachineAppConfig::{
@@ -160,6 +161,7 @@
         ..Default::default()
     };
 
+    let cpu_options = CpuOptions { cpuTopology: config.common.cpu_topology };
     if config.debug.enable_earlycon() {
         if config.debug.debug != DebugLevel::FULL {
             bail!("earlycon is only supported for debuggable VMs")
@@ -188,7 +190,7 @@
         debugLevel: config.debug.debug,
         protectedVm: config.common.protected,
         memoryMib: config.common.mem.unwrap_or(0) as i32, // 0 means use the VM default
-        cpuTopology: config.common.cpu_topology,
+        cpuOptions: cpu_options,
         customConfig: Some(custom_config),
         osName: os_name.to_string(),
         hugePages: config.common.hugepages,
@@ -273,7 +275,7 @@
     if let Some(gdb) = config.debug.gdb {
         vm_config.gdbPort = gdb.get() as i32;
     }
-    vm_config.cpuTopology = config.common.cpu_topology;
+    vm_config.cpuOptions = CpuOptions { cpuTopology: config.common.cpu_topology.clone() };
     vm_config.hugePages = config.common.hugepages;
     vm_config.boostUclamp = config.common.boost_uclamp;
     vm_config.teeServices = config.common.tee_services().to_vec();
diff --git a/build/debian/fai_config/package_config/AVF b/build/debian/fai_config/package_config/AVF
index bf51fdb..ec68434 100644
--- a/build/debian/fai_config/package_config/AVF
+++ b/build/debian/fai_config/package_config/AVF
@@ -10,3 +10,6 @@
 shutdown-runner
 weston
 xwayland
+mesa-vulkan-drivers
+libvulkan1
+vulkan-tools
diff --git a/build/microdroid/bootconfig.x86_64_16k b/build/microdroid/bootconfig.x86_64_16k
index ee01de5..964a5fc 100644
--- a/build/microdroid/bootconfig.x86_64_16k
+++ b/build/microdroid/bootconfig.x86_64_16k
@@ -1 +1 @@
-page_shift = 14
+kernel.page_shift = 14
diff --git a/guest/trusty/security_vm/launcher/src/main.rs b/guest/trusty/security_vm/launcher/src/main.rs
index 8dd7c43..3c8d599 100644
--- a/guest/trusty/security_vm/launcher/src/main.rs
+++ b/guest/trusty/security_vm/launcher/src/main.rs
@@ -15,8 +15,9 @@
 //! A client for trusty security VMs during early boot.
 
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
-    CpuTopology::CpuTopology, IVirtualizationService::IVirtualizationService,
-    VirtualMachineConfig::VirtualMachineConfig, VirtualMachineRawConfig::VirtualMachineRawConfig,
+    CpuOptions::CpuOptions, CpuOptions::CpuTopology::CpuTopology,
+    IVirtualizationService::IVirtualizationService, VirtualMachineConfig::VirtualMachineConfig,
+    VirtualMachineRawConfig::VirtualMachineRawConfig,
 };
 use android_system_virtualizationservice::binder::{ParcelFileDescriptor, Strong};
 use anyhow::{Context, Result};
@@ -61,8 +62,8 @@
 
 fn parse_cpu_topology(s: &str) -> Result<CpuTopology, String> {
     match s {
-        "one-cpu" => Ok(CpuTopology::ONE_CPU),
-        "match-host" => Ok(CpuTopology::MATCH_HOST),
+        "one-cpu" => Ok(CpuTopology::CpuCount(1)),
+        "match-host" => Ok(CpuTopology::MatchHost(true)),
         _ => Err(format!("Invalid cpu topology {}", s)),
     }
 }
@@ -86,7 +87,7 @@
         bootloader,
         protectedVm: args.protected,
         memoryMib: args.memory_size_mib,
-        cpuTopology: args.cpu_topology,
+        cpuOptions: CpuOptions { cpuTopology: args.cpu_topology },
         platformVersion: "~1.0".to_owned(),
         // TODO: add instanceId
         ..Default::default()
diff --git a/libs/dice/open_dice/Android.bp b/libs/dice/open_dice/Android.bp
index 75f70c3..986f496 100644
--- a/libs/dice/open_dice/Android.bp
+++ b/libs/dice/open_dice/Android.bp
@@ -170,6 +170,7 @@
         "libopen_dice_cbor_bindgen.rust_defaults",
     ],
     whole_static_libs: ["libopen_dice_cbor"],
+    shared_libs: ["libcrypto"],
 }
 
 rust_bindgen {
diff --git a/libs/dice/sample_inputs/rules.mk b/libs/dice/sample_inputs/rules.mk
new file mode 100644
index 0000000..72caf11
--- /dev/null
+++ b/libs/dice/sample_inputs/rules.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2025 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.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS := $(LOCAL_DIR)/src/lib.rs
+
+MODULE_CRATE_NAME := diced_sample_inputs
+
+MODULE_LIBRARY_DEPS += \
+	$(call FIND_CRATE,coset) \
+	$(call FIND_CRATE,ciborium) \
+	$(call FIND_CRATE,log) \
+	packages/modules/Virtualization/libs/dice/open_dice \
+
+include make/library.mk
diff --git a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
index 6311168..83b234d 100644
--- a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -41,6 +41,7 @@
 import android.os.PersistableBundle;
 import android.sysprop.HypervisorProperties;
 import android.system.virtualizationservice.AssignedDevices;
+import android.system.virtualizationservice.CpuOptions;
 import android.system.virtualizationservice.DiskImage;
 import android.system.virtualizationservice.Partition;
 import android.system.virtualizationservice.SharedPath;
@@ -806,7 +807,16 @@
                         .orElse(null);
         config.protectedVm = this.mProtectedVm;
         config.memoryMib = bytesToMebiBytes(mMemoryBytes);
-        config.cpuTopology = (byte) this.mCpuTopology;
+        switch (this.mCpuTopology) {
+            case CPU_TOPOLOGY_MATCH_HOST:
+                config.cpuOptions = new CpuOptions();
+                config.cpuOptions.cpuTopology = CpuOptions.CpuTopology.matchHost(true);
+                break;
+            default:
+                config.cpuOptions = new CpuOptions();
+                config.cpuOptions.cpuTopology = CpuOptions.CpuTopology.cpuCount(1);
+                break;
+        }
         config.consoleInputDevice = mConsoleInputDevice;
         config.devices = AssignedDevices.devices(EMPTY_STRING_ARRAY);
         config.platformVersion = "~1.0";
@@ -867,10 +877,12 @@
         vsConfig.memoryMib = bytesToMebiBytes(mMemoryBytes);
         switch (mCpuTopology) {
             case CPU_TOPOLOGY_MATCH_HOST:
-                vsConfig.cpuTopology = android.system.virtualizationservice.CpuTopology.MATCH_HOST;
+                vsConfig.cpuOptions = new CpuOptions();
+                vsConfig.cpuOptions.cpuTopology = CpuOptions.CpuTopology.matchHost(true);
                 break;
             default:
-                vsConfig.cpuTopology = android.system.virtualizationservice.CpuTopology.ONE_CPU;
+                vsConfig.cpuOptions = new CpuOptions();
+                vsConfig.cpuOptions.cpuTopology = CpuOptions.CpuTopology.cpuCount(1);
                 break;
         }
 
diff --git a/libs/libavf/src/lib.rs b/libs/libavf/src/lib.rs
index 6532ace..3fa1b75 100644
--- a/libs/libavf/src/lib.rs
+++ b/libs/libavf/src/lib.rs
@@ -23,7 +23,8 @@
 
 use android_system_virtualizationservice::{
     aidl::android::system::virtualizationservice::{
-        AssignedDevices::AssignedDevices, CpuTopology::CpuTopology, DiskImage::DiskImage,
+        AssignedDevices::AssignedDevices, CpuOptions::CpuOptions,
+        CpuOptions::CpuTopology::CpuTopology, DiskImage::DiskImage,
         IVirtualizationService::IVirtualizationService, VirtualMachineConfig::VirtualMachineConfig,
         VirtualMachineRawConfig::VirtualMachineRawConfig,
     },
@@ -218,8 +219,7 @@
     // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
     // AVirtualMachineRawConfig_create. It's the only reference to the object.
     let config = unsafe { &mut *config };
-    config.cpuTopology = CpuTopology::CUSTOM;
-    config.customVcpuCount = n;
+    config.cpuOptions = CpuOptions { cpuTopology: CpuTopology::CpuCount(n) };
 }
 
 /// Set whether a virtual machine is protected or not.
diff --git a/libs/libcompos_common/compos_client.rs b/libs/libcompos_common/compos_client.rs
index 6872582..a52104d 100644
--- a/libs/libcompos_common/compos_client.rs
+++ b/libs/libcompos_common/compos_client.rs
@@ -22,7 +22,8 @@
     COMPOS_APEX_ROOT, COMPOS_VSOCK_PORT,
 };
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
-    CpuTopology::CpuTopology,
+    CpuOptions::CpuOptions,
+    CpuOptions::CpuTopology::CpuTopology,
     IVirtualizationService::IVirtualizationService,
     VirtualMachineAppConfig::{
         CustomConfig::CustomConfig, DebugLevel::DebugLevel, Payload::Payload,
@@ -120,9 +121,10 @@
         let debug_level = if parameters.debug_mode { DebugLevel::FULL } else { DebugLevel::NONE };
 
         let cpu_topology = match parameters.cpu_topology {
-            VmCpuTopology::OneCpu => CpuTopology::ONE_CPU,
-            VmCpuTopology::MatchHost => CpuTopology::MATCH_HOST,
+            VmCpuTopology::OneCpu => CpuTopology::CpuCount(1),
+            VmCpuTopology::MatchHost => CpuTopology::MatchHost(true),
         };
+        let cpu_options = CpuOptions { cpuTopology: cpu_topology };
 
         // The CompOS VM doesn't need to be updatable (by design it should run exactly twice,
         // with the same APKs and APEXes each time). And having it so causes some interesting
@@ -141,7 +143,7 @@
             extraIdsigs: extra_idsigs,
             protectedVm: true,
             memoryMib: parameters.memory_mib.unwrap_or(0), // 0 means use the default
-            cpuTopology: cpu_topology,
+            cpuOptions: cpu_options,
             customConfig: custom_config,
             ..Default::default()
         });
diff --git a/libs/libservice_vm_manager/src/lib.rs b/libs/libservice_vm_manager/src/lib.rs
index 0f322bb..667731f 100644
--- a/libs/libservice_vm_manager/src/lib.rs
+++ b/libs/libservice_vm_manager/src/lib.rs
@@ -17,7 +17,7 @@
 
 use android_system_virtualizationservice::{
     aidl::android::system::virtualizationservice::{
-        CpuTopology::CpuTopology, DiskImage::DiskImage,
+        CpuOptions::CpuOptions, CpuOptions::CpuTopology::CpuTopology, DiskImage::DiskImage,
         IVirtualizationService::IVirtualizationService, Partition::Partition,
         PartitionType::PartitionType, VirtualMachineConfig::VirtualMachineConfig,
         VirtualMachineRawConfig::VirtualMachineRawConfig,
@@ -226,6 +226,7 @@
         writable: true,
         guid: None,
     }];
+    let cpu_options = CpuOptions { cpuTopology: CpuTopology::CpuCount(1) };
     let rialto = File::open(RIALTO_PATH).context("Failed to open Rialto kernel binary")?;
     let instance_id_file = Path::new(VIRT_DATA_DIR).join(INSTANCE_ID_FILENAME);
     let instance_id = get_or_allocate_instance_id(service.as_ref(), instance_id_file)?;
@@ -236,7 +237,7 @@
         instanceId: instance_id,
         protectedVm: true,
         memoryMib: VM_MEMORY_MB,
-        cpuTopology: CpuTopology::ONE_CPU,
+        cpuOptions: cpu_options,
         platformVersion: "~1.0".to_string(),
         gdbPort: 0, // No gdb
         ..Default::default()
diff --git a/libs/libvmbase/src/arch/aarch64/platform.rs b/libs/libvmbase/src/arch/aarch64/platform.rs
index 6a62f8c..b33df68 100644
--- a/libs/libvmbase/src/arch/aarch64/platform.rs
+++ b/libs/libvmbase/src/arch/aarch64/platform.rs
@@ -106,7 +106,7 @@
 ///
 /// Panics if console was not initialized by calling [`init`] first.
 pub fn uart(id: usize) -> &'static spin::mutex::SpinMutex<Uart> {
-    return CONSOLES[id].get().unwrap();
+    CONSOLES[id].get().unwrap()
 }
 
 /// Reinitializes the emergency UART driver and returns it.
diff --git a/libs/vmconfig/src/lib.rs b/libs/vmconfig/src/lib.rs
index 8357f99..859ca77 100644
--- a/libs/vmconfig/src/lib.rs
+++ b/libs/vmconfig/src/lib.rs
@@ -15,14 +15,14 @@
 //! Struct for VM configuration with JSON (de)serialization and AIDL parcelables
 
 use android_system_virtualizationservice::{
-    aidl::android::system::virtualizationservice::AssignedDevices::AssignedDevices,
-    aidl::android::system::virtualizationservice::CpuTopology::CpuTopology,
-    aidl::android::system::virtualizationservice::DiskImage::DiskImage as AidlDiskImage,
-    aidl::android::system::virtualizationservice::Partition::Partition as AidlPartition,
-    aidl::android::system::virtualizationservice::UsbConfig::UsbConfig as AidlUsbConfig,
-    aidl::android::system::virtualizationservice::VirtualMachineAppConfig::DebugLevel::DebugLevel,
-    aidl::android::system::virtualizationservice::VirtualMachineConfig::VirtualMachineConfig,
-    aidl::android::system::virtualizationservice::VirtualMachineRawConfig::VirtualMachineRawConfig,
+    aidl::android::system::virtualizationservice::{
+        AssignedDevices::AssignedDevices, CpuOptions::CpuOptions,
+        CpuOptions::CpuTopology::CpuTopology, DiskImage::DiskImage as AidlDiskImage,
+        Partition::Partition as AidlPartition, UsbConfig::UsbConfig as AidlUsbConfig,
+        VirtualMachineAppConfig::DebugLevel::DebugLevel,
+        VirtualMachineConfig::VirtualMachineConfig,
+        VirtualMachineRawConfig::VirtualMachineRawConfig,
+    },
     binder::ParcelFileDescriptor,
 };
 
@@ -109,11 +109,12 @@
             0
         };
         let cpu_topology = match self.cpu_topology.as_deref() {
-            None => CpuTopology::ONE_CPU,
-            Some("one_cpu") => CpuTopology::ONE_CPU,
-            Some("match_host") => CpuTopology::MATCH_HOST,
+            None => CpuTopology::CpuCount(1),
+            Some("one_cpu") => CpuTopology::CpuCount(1),
+            Some("match_host") => CpuTopology::MatchHost(true),
             Some(cpu_topology) => bail!("Invalid cpu topology {}", cpu_topology),
         };
+        let cpu_options = CpuOptions { cpuTopology: cpu_topology };
         let usb_config = self.usb_config.clone().map(|x| x.to_parcelable()).transpose()?;
         Ok(VirtualMachineRawConfig {
             kernel: maybe_open_parcel_file(&self.kernel, false)?,
@@ -123,7 +124,7 @@
             disks: self.disks.iter().map(DiskImage::to_parcelable).collect::<Result<_, Error>>()?,
             protectedVm: self.protected,
             memoryMib: memory_mib,
-            cpuTopology: cpu_topology,
+            cpuOptions: cpu_options,
             platformVersion: self.platform_version.to_string(),
             devices: AssignedDevices::Devices(
                 self.devices
diff --git a/microfuchsia/microfuchsiad/src/instance_starter.rs b/microfuchsia/microfuchsiad/src/instance_starter.rs
index e3c4e8d..55c946e 100644
--- a/microfuchsia/microfuchsiad/src/instance_starter.rs
+++ b/microfuchsia/microfuchsiad/src/instance_starter.rs
@@ -17,8 +17,9 @@
 //! Responsible for starting an instance of the Microfuchsia VM.
 
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
-    CpuTopology::CpuTopology, IVirtualizationService::IVirtualizationService,
-    VirtualMachineConfig::VirtualMachineConfig, VirtualMachineRawConfig::VirtualMachineRawConfig,
+    CpuOptions::CpuOptions, CpuOptions::CpuTopology::CpuTopology,
+    IVirtualizationService::IVirtualizationService, VirtualMachineConfig::VirtualMachineConfig,
+    VirtualMachineRawConfig::VirtualMachineRawConfig,
 };
 use anyhow::{ensure, Context, Result};
 use binder::{LazyServiceGuard, ParcelFileDescriptor};
@@ -82,7 +83,7 @@
             disks: vec![],
             protectedVm: false,
             memoryMib: 256,
-            cpuTopology: CpuTopology::ONE_CPU,
+            cpuOptions: CpuOptions { cpuTopology: CpuTopology::CpuCount(1) },
             platformVersion: "1.0.0".into(),
             #[cfg(enable_console)]
             consoleInputDevice: Some("ttyS0".into()),
diff --git a/tests/backcompat_test/src/main.rs b/tests/backcompat_test/src/main.rs
index aa69eec..b0cd042 100644
--- a/tests/backcompat_test/src/main.rs
+++ b/tests/backcompat_test/src/main.rs
@@ -16,7 +16,8 @@
 
 use android_system_virtualizationservice::{
     aidl::android::system::virtualizationservice::{
-        CpuTopology::CpuTopology, DiskImage::DiskImage, VirtualMachineConfig::VirtualMachineConfig,
+        CpuOptions::CpuOptions, CpuOptions::CpuTopology::CpuTopology, DiskImage::DiskImage,
+        VirtualMachineConfig::VirtualMachineConfig,
         VirtualMachineRawConfig::VirtualMachineRawConfig,
     },
     binder::{ParcelFileDescriptor, ProcessState},
@@ -98,7 +99,7 @@
         disks: vec![disk_image, empty_disk_image],
         protectedVm: protected,
         memoryMib: 300,
-        cpuTopology: CpuTopology::ONE_CPU,
+        cpuOptions: CpuOptions { cpuTopology: CpuTopology::CpuCount(1) },
         platformVersion: "~1.0".to_string(),
         ..Default::default()
     });
diff --git a/tests/pvmfw/Android.bp b/tests/pvmfw/Android.bp
index e124e55..7f5f2af 100644
--- a/tests/pvmfw/Android.bp
+++ b/tests/pvmfw/Android.bp
@@ -45,7 +45,7 @@
     ],
     per_testcase_directory: true,
     data: [
-        "assets/bcc.dat",
+        ":test_avf_bcc_dat",
     ],
     device_common_data: [
         ":MicrodroidTestApp",
@@ -59,3 +59,10 @@
     ],
     data_device_bins_first: ["dtc_static"],
 }
+
+filegroup {
+    name: "test_avf_bcc_dat",
+    srcs: [
+        "assets/bcc.dat",
+    ],
+}
diff --git a/tests/vmbase_example/src/main.rs b/tests/vmbase_example/src/main.rs
index cbe90d8..81812cd 100644
--- a/tests/vmbase_example/src/main.rs
+++ b/tests/vmbase_example/src/main.rs
@@ -16,7 +16,8 @@
 
 use android_system_virtualizationservice::{
     aidl::android::system::virtualizationservice::{
-        CpuTopology::CpuTopology, DiskImage::DiskImage, VirtualMachineConfig::VirtualMachineConfig,
+        CpuOptions::CpuOptions, CpuOptions::CpuTopology::CpuTopology, DiskImage::DiskImage,
+        VirtualMachineConfig::VirtualMachineConfig,
         VirtualMachineRawConfig::VirtualMachineRawConfig,
     },
     binder::{ParcelFileDescriptor, ProcessState},
@@ -101,7 +102,7 @@
         disks: vec![disk_image, empty_disk_image],
         protectedVm: false,
         memoryMib: 300,
-        cpuTopology: CpuTopology::ONE_CPU,
+        cpuOptions: CpuOptions { cpuTopology: CpuTopology::CpuCount(1) },
         platformVersion: "~1.0".to_string(),
         gdbPort: 0, // no gdb
         ..Default::default()