Merge "Use rdroidtest attribute for loopdevice test cases" into main
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index 5ad7ee1..57779bf 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -819,6 +819,8 @@
             .unwrap_or(Ok(UsbConfig { controller: false }))
             .or_binder_exception(ExceptionCode::BAD_PARCELABLE)?;
 
+        let detect_hangup = is_app_config && gdb_port.is_none();
+
         // Actually start the VM.
         let crosvm_config = CrosvmConfig {
             cid,
@@ -846,7 +848,7 @@
             ramdump,
             indirect_files,
             platform_version: parse_platform_version_req(&config.platformVersion)?,
-            detect_hangup: is_app_config,
+            detect_hangup,
             gdb_port,
             vfio_devices,
             dtbo,
diff --git a/build/debian/build.sh b/build/debian/build.sh
index 3f33ec8..a426d22 100755
--- a/build/debian/build.sh
+++ b/build/debian/build.sh
@@ -156,6 +156,7 @@
 	source "$HOME"/.cargo/env
 	rustup target add "${arch}"-unknown-linux-gnu
 	cargo install cargo-license
+	cargo install cargo-deb
 }
 
 download_debian_cloud_image() {
@@ -168,23 +169,11 @@
 	wget -O - "${url}" | tar xz -C "${outdir}" --strip-components=1
 }
 
-build_rust_binary_and_copy() {
+build_rust_as_deb() {
 	pushd "$(dirname "$0")/../../guest/$1" > /dev/null
-	local release_flag=
-	local artifact_mode=debug
-	if [[ "$mode" == "release" ]]; then
-		release_flag="--release"
-		artifact_mode=release
-	fi
-	RUSTFLAGS="-C linker=${arch}-linux-gnu-gcc" cargo build \
+	cargo deb \
 		--target "${arch}-unknown-linux-gnu" \
-		--target-dir "${workdir}/$1" ${release_flag}
-	mkdir -p "${dst}/files/usr/local/bin/$1"
-	cp "${workdir}/$1/${arch}-unknown-linux-gnu/${artifact_mode}/$1" "${dst}/files/usr/local/bin/$1/AVF"
-	chmod 777 "${dst}/files/usr/local/bin/$1/AVF"
-
-	mkdir -p "${dst}/files/usr/share/doc/$1"
-	cargo license > "${dst}/files/usr/share/doc/$1/copyright"
+		--output "${debian_cloud_image}/localdebs"
 	popd > /dev/null
 }
 
@@ -218,9 +207,9 @@
 
 	cp -R "$(dirname "$0")/localdebs/" "${debian_cloud_image}/"
 	build_ttyd
-	build_rust_binary_and_copy forwarder_guest
-	build_rust_binary_and_copy forwarder_guest_launcher
-	build_rust_binary_and_copy shutdown_runner
+	build_rust_as_deb forwarder_guest
+	build_rust_as_deb forwarder_guest_launcher
+	build_rust_as_deb shutdown_runner
 }
 
 package_custom_kernel() {
diff --git a/build/debian/fai_config/files/etc/systemd/system/shutdown_runner.service/AVF b/build/debian/fai_config/files/etc/systemd/system/shutdown_runner.service/AVF
deleted file mode 100644
index bfb8afb..0000000
--- a/build/debian/fai_config/files/etc/systemd/system/shutdown_runner.service/AVF
+++ /dev/null
@@ -1,11 +0,0 @@
-[Unit]
-After=syslog.target
-After=network.target
-After=virtiofs_internal.service
-[Service]
-ExecStart=/usr/bin/bash -c '/usr/local/bin/shutdown_runner --grpc_port $(cat /mnt/internal/debian_service_port)'
-Type=simple
-User=root
-Group=root
-[Install]
-WantedBy=multi-user.target
diff --git a/build/debian/fai_config/package_config/AVF b/build/debian/fai_config/package_config/AVF
index c779021..98b558b 100644
--- a/build/debian/fai_config/package_config/AVF
+++ b/build/debian/fai_config/package_config/AVF
@@ -5,3 +5,6 @@
 bpfcc-tools
 libnss-mdns
 procps
+forwarder-guest
+forwarder-guest-launcher
+shutdown-runner
diff --git a/build/debian/fai_config/scripts/AVF/10-systemd b/build/debian/fai_config/scripts/AVF/10-systemd
index 998cbfd..121acc5 100755
--- a/build/debian/fai_config/scripts/AVF/10-systemd
+++ b/build/debian/fai_config/scripts/AVF/10-systemd
@@ -1,14 +1,9 @@
 #!/bin/bash
 
-chmod +x $target/usr/local/bin/forwarder_guest
-chmod +x $target/usr/local/bin/forwarder_guest_launcher
-chmod +x $target/usr/local/bin/shutdown_runner
 chmod +x $target/usr/local/bin/ttyd
 ln -s /etc/systemd/system/ttyd.service $target/etc/systemd/system/multi-user.target.wants/ttyd.service
 ln -s /etc/systemd/system/virtiofs.service $target/etc/systemd/system/multi-user.target.wants/virtiofs.service
-ln -s /etc/systemd/system/forwarder_guest_launcher.service $target/etc/systemd/system/multi-user.target.wants/forwarder_guest_launcher.service
 ln -s /etc/systemd/system/virtiofs_internal.service $target/etc/systemd/system/multi-user.target.wants/virtiofs_internal.service
 ln -s /etc/systemd/system/backup_mount.service $target/etc/systemd/system/multi-user.target.wants/backup_mount.service
-ln -s /etc/systemd/system/shutdown_runner.service $target/etc/systemd/system/multi-user.target.wants/shutdown_runner.service
 
 sed -i 's/#LLMNR=yes/LLMNR=no/' $target/etc/systemd/resolved.conf
diff --git a/guest/forwarder_guest/.cargo/config.toml b/guest/forwarder_guest/.cargo/config.toml
new file mode 100644
index 0000000..a451cda
--- /dev/null
+++ b/guest/forwarder_guest/.cargo/config.toml
@@ -0,0 +1,6 @@
+[target.aarch64-unknown-linux-gnu]
+linker = "aarch64-linux-gnu-gcc"
+rustflags = ["-C", "target-feature=+crt-static"]
+
+[target.x86_64-unknown-linux-gnu]
+rustflags = ["-C", "target-feature=+crt-static"]
diff --git a/guest/forwarder_guest/Cargo.toml b/guest/forwarder_guest/Cargo.toml
index ce50e4c..bb9b826 100644
--- a/guest/forwarder_guest/Cargo.toml
+++ b/guest/forwarder_guest/Cargo.toml
@@ -10,3 +10,8 @@
 poll_token_derive = "0.1.0"
 remain = "0.2.14"
 vmm-sys-util = "0.12.1"
+
+[package.metadata.deb]
+maintainer = "ferrochrome-dev@google.com"
+copyright = "2024, The Android Open Source Project"
+depends = "$auto"
diff --git a/guest/forwarder_guest_launcher/.cargo/config.toml b/guest/forwarder_guest_launcher/.cargo/config.toml
new file mode 100644
index 0000000..a451cda
--- /dev/null
+++ b/guest/forwarder_guest_launcher/.cargo/config.toml
@@ -0,0 +1,6 @@
+[target.aarch64-unknown-linux-gnu]
+linker = "aarch64-linux-gnu-gcc"
+rustflags = ["-C", "target-feature=+crt-static"]
+
+[target.x86_64-unknown-linux-gnu]
+rustflags = ["-C", "target-feature=+crt-static"]
diff --git a/guest/forwarder_guest_launcher/Cargo.toml b/guest/forwarder_guest_launcher/Cargo.toml
index aef27f9..9c4d7e3 100644
--- a/guest/forwarder_guest_launcher/Cargo.toml
+++ b/guest/forwarder_guest_launcher/Cargo.toml
@@ -21,3 +21,10 @@
 
 [build-dependencies]
 tonic-build = "0.12.3"
+
+[package.metadata.deb]
+maintainer = "ferrochrome-dev@google.com"
+copyright = "2024, The Android Open Source Project"
+depends = "$auto"
+maintainer-scripts = "debian/"
+systemd-units = { }
diff --git a/build/debian/fai_config/files/etc/systemd/system/forwarder_guest_launcher.service/AVF b/guest/forwarder_guest_launcher/debian/service
similarity index 65%
rename from build/debian/fai_config/files/etc/systemd/system/forwarder_guest_launcher.service/AVF
rename to guest/forwarder_guest_launcher/debian/service
index 129fdad..6824c70 100644
--- a/build/debian/fai_config/files/etc/systemd/system/forwarder_guest_launcher.service/AVF
+++ b/guest/forwarder_guest_launcher/debian/service
@@ -3,12 +3,14 @@
 After=syslog.target
 After=network.target
 After=virtiofs_internal.service
+
 [Service]
-ExecStart=/usr/bin/bash -c '/usr/local/bin/forwarder_guest_launcher --grpc_port $(cat /mnt/internal/debian_service_port)'
+ExecStart=/usr/bin/bash -c '/usr/bin/forwarder_guest_launcher --grpc_port $(cat /mnt/internal/debian_service_port)'
 Type=simple
 Restart=on-failure
 RestartSec=1
 User=root
 Group=root
+
 [Install]
 WantedBy=multi-user.target
diff --git a/guest/microdroid_manager/src/dice.rs b/guest/microdroid_manager/src/dice.rs
index edc4d63..bf89358 100644
--- a/guest/microdroid_manager/src/dice.rs
+++ b/guest/microdroid_manager/src/dice.rs
@@ -153,7 +153,8 @@
             subcomponents.into_iter().map(Subcomponent::into_value).collect::<Result<Vec<_>>>()?;
         map.push((cbor!(-71002)?, cbor!(values)?));
     }
-
+    // Add a placeholder security version as it is required by the open-dice profile "Android.16"
+    map.push((cbor!(-70005)?, cbor!(0)?));
     Ok(Value::Map(map).to_vec()?)
 }
 
@@ -180,10 +181,10 @@
         let config_descriptor =
             format_payload_config_descriptor(&payload_metadata, NO_SUBCOMPONENTS)?;
         static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
-            0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
+            0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
             0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
             0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
-            0x68,
+            0x68, 0x3a, 0x00, 0x01, 0x11, 0x74, 0x00,
         ];
         assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
         Ok(())
@@ -199,10 +200,10 @@
         let config_descriptor =
             format_payload_config_descriptor(&payload_metadata, NO_SUBCOMPONENTS)?;
         static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
-            0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
+            0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
             0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
             0x15, 0x58, 0xa1, 0x01, 0x6e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62,
-            0x69, 0x6e, 0x61, 0x72, 0x79,
+            0x69, 0x6e, 0x61, 0x72, 0x79, 0x3a, 0x00, 0x01, 0x11, 0x74, 0x00,
         ];
         assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
         Ok(())
@@ -228,13 +229,13 @@
         let config_descriptor = format_payload_config_descriptor(&payload_metadata, subcomponents)?;
         // Verified using cbor.me.
         static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
-            0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
+            0xa4, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
             0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
             0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
             0x68, 0x3a, 0x00, 0x01, 0x15, 0x59, 0x82, 0xa4, 0x01, 0x64, 0x61, 0x70, 0x6b, 0x31,
             0x02, 0x01, 0x03, 0x42, 0x2a, 0x2b, 0x04, 0x41, 0x11, 0xa4, 0x01, 0x64, 0x61, 0x70,
             0x6b, 0x32, 0x02, 0x1b, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x41,
-            0x2b, 0x04, 0x42, 0x13, 0x14,
+            0x2b, 0x04, 0x42, 0x13, 0x14, 0x3a, 0x00, 0x01, 0x11, 0x74, 0x00,
         ];
         assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
         Ok(())
diff --git a/guest/pvmfw/avb/tests/utils.rs b/guest/pvmfw/avb/tests/utils.rs
index 79552b5..e8590ac 100644
--- a/guest/pvmfw/avb/tests/utils.rs
+++ b/guest/pvmfw/avb/tests/utils.rs
@@ -124,8 +124,7 @@
     let footer = extract_avb_footer(&kernel)?;
     let kernel_digest =
         hash(&[&hash(&[b"bootloader"]), &kernel[..usize::try_from(footer.original_image_size)?]]);
-    let capabilities =
-        if cfg!(llpvm_changes) { vec![Capability::SecretkeeperProtection] } else { vec![] };
+    let capabilities = vec![Capability::SecretkeeperProtection];
     let initrd_digest = Some(hash(&[&hash(&[initrd_salt]), initrd]));
     let expected_boot_data = VerifiedBootData {
         debug_level: expected_debug_level,
@@ -133,7 +132,7 @@
         initrd_digest,
         public_key: &public_key,
         capabilities,
-        rollback_index: if cfg!(llpvm_changes) { 1 } else { 0 },
+        rollback_index: 1,
         page_size,
     };
     assert_eq!(expected_boot_data, verified_boot_data);
diff --git a/guest/pvmfw/src/main.rs b/guest/pvmfw/src/main.rs
index 5ff9c4c..0a3dca6 100644
--- a/guest/pvmfw/src/main.rs
+++ b/guest/pvmfw/src/main.rs
@@ -129,7 +129,7 @@
         RebootReason::InternalError
     })?;
 
-    let instance_hash = if cfg!(llpvm_changes) { Some(salt_from_instance_id(fdt)?) } else { None };
+    let instance_hash = Some(salt_from_instance_id(fdt)?);
     let (new_instance, salt, defer_rollback_protection) = perform_rollback_protection(
         fdt,
         &verified_boot_data,
diff --git a/guest/pvmfw/src/rollback.rs b/guest/pvmfw/src/rollback.rs
index 15d22b3..f7723d7 100644
--- a/guest/pvmfw/src/rollback.rs
+++ b/guest/pvmfw/src/rollback.rs
@@ -30,7 +30,7 @@
 /// Performs RBP based on the input payload, current DICE chain, and host-controlled platform.
 ///
 /// On success, returns a tuple containing:
-/// - `new_instance`: true if a new entry was created using the legacy instance.img solution;
+/// - `new_instance`: true if the legacy instance.img solution was used and a new entry created;
 /// - `salt`: the salt representing the instance, to be used during DICE derivation;
 /// - `defer_rollback_protection`: if RBP is being deferred.
 pub fn perform_rollback_protection(
@@ -41,67 +41,87 @@
     cdi_seal: &[u8],
     instance_hash: Option<Hidden>,
 ) -> Result<(bool, Hidden, bool), RebootReason> {
-    let defer_rollback_protection = should_defer_rollback_protection(fdt)?
-        && verified_boot_data.has_capability(Capability::SecretkeeperProtection);
-    let (new_instance, salt) = if defer_rollback_protection {
-        info!("Guest OS is capable of Secretkeeper protection, deferring rollback protection");
-        // rollback_index of the image is used as security_version and is expected to be > 0 to
-        // discourage implicit allocation.
-        if verified_boot_data.rollback_index == 0 {
-            error!("Expected positive rollback_index, found 0");
-            return Err(RebootReason::InvalidPayload);
-        };
-        (false, instance_hash.unwrap())
+    if should_defer_rollback_protection(fdt)?
+        && verified_boot_data.has_capability(Capability::SecretkeeperProtection)
+    {
+        perform_deferred_rollback_protection(verified_boot_data)?;
+        Ok((false, instance_hash.unwrap(), true))
     } else if verified_boot_data.has_capability(Capability::RemoteAttest) {
-        info!("Service VM capable of remote attestation detected, performing version checks");
-        if service_vm_version::VERSION != verified_boot_data.rollback_index {
-            // For RKP VM, we only boot if the version in the AVB footer of its kernel matches
-            // the one embedded in pvmfw at build time.
-            // This prevents the pvmfw from booting a roll backed RKP VM.
-            error!(
-                "Service VM version mismatch: expected {}, found {}",
-                service_vm_version::VERSION,
-                verified_boot_data.rollback_index
-            );
-            return Err(RebootReason::InvalidPayload);
-        }
-        (false, instance_hash.unwrap())
+        perform_fixed_index_rollback_protection(verified_boot_data)?;
+        Ok((false, instance_hash.unwrap(), false))
     } else if verified_boot_data.has_capability(Capability::TrustySecurityVm) {
-        // The rollback protection of Trusty VMs are handled by AuthMgr, so we don't need to
-        // handle it here.
-        info!("Trusty Security VM detected");
-        (false, instance_hash.unwrap())
+        skip_rollback_protection()?;
+        Ok((false, instance_hash.unwrap(), false))
     } else {
-        info!("Fallback to instance.img based rollback checks");
-        let (recorded_entry, mut instance_img, header_index) =
-            get_recorded_entry(pci_root, cdi_seal).map_err(|e| {
-                error!("Failed to get entry from instance.img: {e}");
-                RebootReason::InternalError
-            })?;
-        let (new_instance, salt) = if let Some(entry) = recorded_entry {
-            check_dice_measurements_match_entry(dice_inputs, &entry)?;
-            let salt = instance_hash.unwrap_or(entry.salt);
-            (false, salt)
-        } else {
-            // New instance!
-            let salt = instance_hash.map_or_else(rand::random_array, Ok).map_err(|e| {
-                error!("Failed to generated instance.img salt: {e}");
-                RebootReason::InternalError
-            })?;
+        perform_legacy_rollback_protection(dice_inputs, pci_root, cdi_seal, instance_hash)
+    }
+}
 
-            let entry = EntryBody::new(dice_inputs, &salt);
-            record_instance_entry(&entry, cdi_seal, &mut instance_img, header_index).map_err(
-                |e| {
-                    error!("Failed to get recorded entry in instance.img: {e}");
-                    RebootReason::InternalError
-                },
-            )?;
-            (true, salt)
-        };
-        (new_instance, salt)
+fn perform_deferred_rollback_protection(
+    verified_boot_data: &VerifiedBootData,
+) -> Result<(), RebootReason> {
+    info!("Deferring rollback protection");
+    // rollback_index of the image is used as security_version and is expected to be > 0 to
+    // discourage implicit allocation.
+    if verified_boot_data.rollback_index == 0 {
+        error!("Expected positive rollback_index, found 0");
+        Err(RebootReason::InvalidPayload)
+    } else {
+        Ok(())
+    }
+}
+
+fn perform_fixed_index_rollback_protection(
+    verified_boot_data: &VerifiedBootData,
+) -> Result<(), RebootReason> {
+    info!("Performing fixed-index rollback protection");
+    let fixed_index = service_vm_version::VERSION;
+    let index = verified_boot_data.rollback_index;
+    if index != fixed_index {
+        error!("Rollback index mismatch: expected {fixed_index}, found {index}");
+        Err(RebootReason::InvalidPayload)
+    } else {
+        Ok(())
+    }
+}
+
+fn skip_rollback_protection() -> Result<(), RebootReason> {
+    info!("Skipping rollback protection");
+    Ok(())
+}
+
+/// Performs RBP using instance.img where updates require clearing old entries, causing new CDIs.
+fn perform_legacy_rollback_protection(
+    dice_inputs: &PartialInputs,
+    pci_root: &mut PciRoot,
+    cdi_seal: &[u8],
+    instance_hash: Option<Hidden>,
+) -> Result<(bool, Hidden, bool), RebootReason> {
+    info!("Fallback to instance.img based rollback checks");
+    let (recorded_entry, mut instance_img, header_index) = get_recorded_entry(pci_root, cdi_seal)
+        .map_err(|e| {
+        error!("Failed to get entry from instance.img: {e}");
+        RebootReason::InternalError
+    })?;
+    let (new_instance, salt) = if let Some(entry) = recorded_entry {
+        check_dice_measurements_match_entry(dice_inputs, &entry)?;
+        let salt = instance_hash.unwrap_or(entry.salt);
+        (false, salt)
+    } else {
+        // New instance!
+        let salt = instance_hash.map_or_else(rand::random_array, Ok).map_err(|e| {
+            error!("Failed to generated instance.img salt: {e}");
+            RebootReason::InternalError
+        })?;
+
+        let entry = EntryBody::new(dice_inputs, &salt);
+        record_instance_entry(&entry, cdi_seal, &mut instance_img, header_index).map_err(|e| {
+            error!("Failed to get recorded entry in instance.img: {e}");
+            RebootReason::InternalError
+        })?;
+        (true, salt)
     };
-
-    Ok((new_instance, salt, defer_rollback_protection))
+    Ok((new_instance, salt, false))
 }
 
 fn check_dice_measurements_match_entry(
diff --git a/guest/shutdown_runner/.cargo/config.toml b/guest/shutdown_runner/.cargo/config.toml
new file mode 100644
index 0000000..a451cda
--- /dev/null
+++ b/guest/shutdown_runner/.cargo/config.toml
@@ -0,0 +1,6 @@
+[target.aarch64-unknown-linux-gnu]
+linker = "aarch64-linux-gnu-gcc"
+rustflags = ["-C", "target-feature=+crt-static"]
+
+[target.x86_64-unknown-linux-gnu]
+rustflags = ["-C", "target-feature=+crt-static"]
diff --git a/guest/shutdown_runner/Cargo.toml b/guest/shutdown_runner/Cargo.toml
index b74e7ee..0b44baa 100644
--- a/guest/shutdown_runner/Cargo.toml
+++ b/guest/shutdown_runner/Cargo.toml
@@ -15,3 +15,10 @@
 
 [build-dependencies]
 tonic-build = "0.12.3"
+
+[package.metadata.deb]
+maintainer = "ferrochrome-dev@google.com"
+copyright = "2024, The Android Open Source Project"
+depends = "$auto"
+maintainer-scripts = "debian/"
+systemd-units = { }
diff --git a/guest/shutdown_runner/debian/service b/guest/shutdown_runner/debian/service
new file mode 100644
index 0000000..d19ff25
--- /dev/null
+++ b/guest/shutdown_runner/debian/service
@@ -0,0 +1,13 @@
+[Unit]
+After=syslog.target
+After=network.target
+After=virtiofs_internal.service
+
+[Service]
+ExecStart=/usr/bin/bash -c '/usr/bin/shutdown_runner --grpc_port $(cat /mnt/internal/debian_service_port)'
+Type=simple
+User=root
+Group=root
+
+[Install]
+WantedBy=multi-user.target
diff --git a/libs/dice/sample_inputs/src/sample_inputs.rs b/libs/dice/sample_inputs/src/sample_inputs.rs
index 54f551b..c323bc4 100644
--- a/libs/dice/sample_inputs/src/sample_inputs.rs
+++ b/libs/dice/sample_inputs/src/sample_inputs.rs
@@ -118,6 +118,7 @@
         component_name: Some(CStr::from_bytes_with_nul(b"ABL\0").unwrap()),
         component_version: Some(1),
         resettable: true,
+        security_version: Some(10),
         ..Default::default()
     };
     let config_descriptor = retry_bcc_format_config_descriptor(&config_values)?;
@@ -150,6 +151,7 @@
         component_name: Some(CStr::from_bytes_with_nul(b"AVB\0").unwrap()),
         component_version: Some(1),
         resettable: true,
+        security_version: Some(11),
         ..Default::default()
     };
     let config_descriptor = retry_bcc_format_config_descriptor(&config_values)?;
@@ -174,6 +176,7 @@
         component_name: Some(CStr::from_bytes_with_nul(b"Android\0").unwrap()),
         component_version: Some(12),
         resettable: true,
+        security_version: Some(12),
         ..Default::default()
     };
     let config_descriptor = retry_bcc_format_config_descriptor(&config_values)?;
diff --git a/libs/dice/sample_inputs/tests/api_test.rs b/libs/dice/sample_inputs/tests/api_test.rs
index c627824..566d3c7 100644
--- a/libs/dice/sample_inputs/tests/api_test.rs
+++ b/libs/dice/sample_inputs/tests/api_test.rs
@@ -22,8 +22,8 @@
 use hwtrust::{dice, session::Session};
 
 const EXPECTED_SAMPLE_CDI_ATTEST: &[u8] = &[
-    0x3e, 0x57, 0x65, 0x5d, 0x48, 0x02, 0xbd, 0x5c, 0x66, 0xcc, 0x1f, 0x0f, 0xbe, 0x5e, 0x32, 0xb6,
-    0x9e, 0x3d, 0x04, 0xaf, 0x00, 0x15, 0xbc, 0xdd, 0x1f, 0xbc, 0x59, 0xe4, 0xc3, 0x87, 0x95, 0x5e,
+    0xb2, 0x13, 0xde, 0x86, 0xf7, 0x40, 0x7b, 0xd5, 0x20, 0x21, 0x74, 0x4e, 0x75, 0x78, 0x1a, 0xcb,
+    0x22, 0x57, 0x1c, 0x32, 0xa4, 0x1e, 0xc9, 0x23, 0x73, 0x5b, 0x9c, 0x6b, 0x5f, 0x6b, 0x2d, 0xc0,
 ];
 
 const EXPECTED_SAMPLE_CDI_SEAL: &[u8] = &[
@@ -35,95 +35,99 @@
     0x84, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x3e, 0x85,
     0xe5, 0x72, 0x75, 0x55, 0xe5, 0x1e, 0xe7, 0xf3, 0x35, 0x94, 0x8e, 0xbb, 0xbd, 0x74, 0x1e, 0x1d,
     0xca, 0x49, 0x9c, 0x97, 0x39, 0x77, 0x06, 0xd3, 0xc8, 0x6e, 0x8b, 0xd7, 0x33, 0xf9, 0x84, 0x43,
-    0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x8a, 0xa9, 0x01, 0x78, 0x28, 0x34, 0x32, 0x64, 0x38, 0x38,
+    0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0xa1, 0xaa, 0x01, 0x78, 0x28, 0x34, 0x32, 0x64, 0x38, 0x38,
     0x36, 0x34, 0x66, 0x39, 0x37, 0x62, 0x36, 0x35, 0x34, 0x37, 0x61, 0x35, 0x30, 0x63, 0x31, 0x65,
     0x30, 0x61, 0x37, 0x34, 0x39, 0x66, 0x38, 0x65, 0x66, 0x38, 0x62, 0x38, 0x31, 0x65, 0x63, 0x36,
-    0x32, 0x61, 0x66, 0x02, 0x78, 0x28, 0x31, 0x66, 0x36, 0x39, 0x36, 0x66, 0x30, 0x37, 0x32, 0x35,
-    0x32, 0x66, 0x32, 0x39, 0x65, 0x39, 0x33, 0x66, 0x65, 0x34, 0x64, 0x65, 0x31, 0x39, 0x65, 0x65,
-    0x33, 0x32, 0x63, 0x64, 0x38, 0x31, 0x64, 0x63, 0x34, 0x30, 0x34, 0x65, 0x37, 0x36, 0x3a, 0x00,
+    0x32, 0x61, 0x66, 0x02, 0x78, 0x28, 0x34, 0x61, 0x61, 0x66, 0x61, 0x38, 0x30, 0x62, 0x30, 0x62,
+    0x30, 0x63, 0x31, 0x33, 0x34, 0x64, 0x31, 0x36, 0x65, 0x36, 0x30, 0x35, 0x36, 0x66, 0x30, 0x35,
+    0x35, 0x32, 0x62, 0x65, 0x65, 0x33, 0x38, 0x61, 0x37, 0x37, 0x30, 0x65, 0x35, 0x62, 0x3a, 0x00,
     0x47, 0x44, 0x50, 0x58, 0x40, 0x16, 0x48, 0xf2, 0x55, 0x53, 0x23, 0xdd, 0x15, 0x2e, 0x83, 0x38,
     0xc3, 0x64, 0x38, 0x63, 0x26, 0x0f, 0xcf, 0x5b, 0xd1, 0x3a, 0xd3, 0x40, 0x3e, 0x23, 0xf8, 0x34,
     0x4c, 0x6d, 0xa2, 0xbe, 0x25, 0x1c, 0xb0, 0x29, 0xe8, 0xc3, 0xfb, 0xb8, 0x80, 0xdc, 0xb1, 0xd2,
     0xb3, 0x91, 0x4d, 0xd3, 0xfb, 0x01, 0x0f, 0xe4, 0xe9, 0x46, 0xa2, 0xc0, 0x26, 0x57, 0x5a, 0xba,
-    0x30, 0xf7, 0x15, 0x98, 0x14, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x56, 0xa3, 0x3a, 0x00, 0x01, 0x11,
-    0x71, 0x63, 0x41, 0x42, 0x4c, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x01, 0x3a, 0x00, 0x01, 0x11, 0x73,
-    0xf6, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x47, 0xae, 0x42, 0x27, 0x4c, 0xcb, 0x65, 0x4d,
-    0xee, 0x74, 0x2d, 0x05, 0x78, 0x2a, 0x08, 0x2a, 0xa5, 0xf0, 0xcf, 0xea, 0x3e, 0x60, 0xee, 0x97,
-    0x11, 0x4b, 0x5b, 0xe6, 0x05, 0x0c, 0xe8, 0x90, 0xf5, 0x22, 0xc4, 0xc6, 0x67, 0x7a, 0x22, 0x27,
-    0x17, 0xb3, 0x79, 0xcc, 0x37, 0x64, 0x5e, 0x19, 0x4f, 0x96, 0x37, 0x67, 0x3c, 0xd0, 0xc5, 0xed,
-    0x0f, 0xdd, 0xe7, 0x2e, 0x4f, 0x70, 0x97, 0x30, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x40, 0xf9,
-    0x00, 0x9d, 0xc2, 0x59, 0x09, 0xe0, 0xb6, 0x98, 0xbd, 0xe3, 0x97, 0x4a, 0xcb, 0x3c, 0xe7, 0x6b,
-    0x24, 0xc3, 0xe4, 0x98, 0xdd, 0xa9, 0x6a, 0x41, 0x59, 0x15, 0xb1, 0x23, 0xe6, 0xc8, 0xdf, 0xfb,
-    0x52, 0xb4, 0x52, 0xc1, 0xb9, 0x61, 0xdd, 0xbc, 0x5b, 0x37, 0x0e, 0x12, 0x12, 0xb2, 0xfd, 0xc1,
-    0x09, 0xb0, 0xcf, 0x33, 0x81, 0x4c, 0xc6, 0x29, 0x1b, 0x99, 0xea, 0xae, 0xfd, 0xaa, 0x0d, 0x3a,
-    0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01,
-    0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0xb1, 0x02, 0xcc, 0x2c, 0xb2, 0x6a,
-    0x3b, 0xe9, 0xc1, 0xd3, 0x95, 0x10, 0xa0, 0xe1, 0xff, 0x51, 0xde, 0x57, 0xd5, 0x65, 0x28, 0xfd,
-    0x7f, 0xeb, 0xd4, 0xca, 0x15, 0xf3, 0xca, 0xdf, 0x37, 0x88, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41,
-    0x20, 0x58, 0x40, 0x58, 0xd8, 0x03, 0x24, 0x53, 0x60, 0x57, 0xa9, 0x09, 0xfa, 0xab, 0xdc, 0x57,
-    0x1e, 0xf0, 0xe5, 0x1e, 0x51, 0x6f, 0x9e, 0xa3, 0x42, 0xe6, 0x6a, 0x8c, 0xaa, 0xad, 0x08, 0x48,
-    0xde, 0x7f, 0x4f, 0x6e, 0x2f, 0x7f, 0x39, 0x6c, 0xa1, 0xf8, 0x42, 0x71, 0xfe, 0x17, 0x3d, 0xca,
-    0x31, 0x83, 0x92, 0xed, 0xbb, 0x40, 0xb8, 0x10, 0xe0, 0xf2, 0x5a, 0x99, 0x53, 0x38, 0x46, 0x33,
-    0x97, 0x78, 0x05, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x8a, 0xa9, 0x01, 0x78, 0x28,
-    0x31, 0x66, 0x36, 0x39, 0x36, 0x66, 0x30, 0x37, 0x32, 0x35, 0x32, 0x66, 0x32, 0x39, 0x65, 0x39,
-    0x33, 0x66, 0x65, 0x34, 0x64, 0x65, 0x31, 0x39, 0x65, 0x65, 0x33, 0x32, 0x63, 0x64, 0x38, 0x31,
-    0x64, 0x63, 0x34, 0x30, 0x34, 0x65, 0x37, 0x36, 0x02, 0x78, 0x28, 0x32, 0x35, 0x39, 0x34, 0x38,
-    0x39, 0x65, 0x36, 0x39, 0x37, 0x34, 0x38, 0x37, 0x30, 0x35, 0x64, 0x65, 0x33, 0x65, 0x32, 0x66,
-    0x34, 0x34, 0x32, 0x36, 0x37, 0x65, 0x61, 0x34, 0x39, 0x33, 0x38, 0x66, 0x66, 0x36, 0x61, 0x35,
-    0x37, 0x32, 0x35, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 0xa4, 0x0c, 0xcb, 0xc1, 0xbf, 0xfa,
-    0xcc, 0xfd, 0xeb, 0xf4, 0xfc, 0x43, 0x83, 0x7f, 0x46, 0x8d, 0xd8, 0xd8, 0x14, 0xc1, 0x96, 0x14,
-    0x1f, 0x6e, 0xb3, 0xa0, 0xd9, 0x56, 0xb3, 0xbf, 0x2f, 0xfa, 0x88, 0x70, 0x11, 0x07, 0x39, 0xa4,
-    0xd2, 0xa9, 0x6b, 0x18, 0x28, 0xe8, 0x29, 0x20, 0x49, 0x0f, 0xbb, 0x8d, 0x08, 0x8c, 0xc6, 0x54,
-    0xe9, 0x71, 0xd2, 0x7e, 0xa4, 0xfe, 0x58, 0x7f, 0xd3, 0xc7, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x56,
-    0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x63, 0x41, 0x56, 0x42, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x01,
-    0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x93, 0x17, 0xe1,
-    0x11, 0x27, 0x59, 0xd0, 0xef, 0x75, 0x0b, 0x2b, 0x1c, 0x0f, 0x5f, 0x52, 0xc3, 0x29, 0x23, 0xb5,
-    0x2a, 0xe6, 0x12, 0x72, 0x6f, 0x39, 0x86, 0x65, 0x2d, 0xf2, 0xe4, 0xe7, 0xd0, 0xaf, 0x0e, 0xa7,
-    0x99, 0x16, 0x89, 0x97, 0x21, 0xf7, 0xdc, 0x89, 0xdc, 0xde, 0xbb, 0x94, 0x88, 0x1f, 0xda, 0xe2,
-    0xf3, 0xe0, 0x54, 0xf9, 0x0e, 0x29, 0xb1, 0xbd, 0xe1, 0x0c, 0x0b, 0xd7, 0xf6, 0x3a, 0x00, 0x47,
-    0x44, 0x54, 0x58, 0x40, 0xb2, 0x69, 0x05, 0x48, 0x56, 0xb5, 0xfa, 0x55, 0x6f, 0xac, 0x56, 0xd9,
-    0x02, 0x35, 0x2b, 0xaa, 0x4c, 0xba, 0x28, 0xdd, 0x82, 0x3a, 0x86, 0xf5, 0xd4, 0xc2, 0xf1, 0xf9,
-    0x35, 0x7d, 0xe4, 0x43, 0x13, 0xbf, 0xfe, 0xd3, 0x36, 0xd8, 0x1c, 0x12, 0x78, 0x5c, 0x9c, 0x3e,
-    0xf6, 0x66, 0xef, 0xab, 0x3d, 0x0f, 0x89, 0xa4, 0x6f, 0xc9, 0x72, 0xee, 0x73, 0x43, 0x02, 0x8a,
-    0xef, 0xbc, 0x05, 0x98, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57,
-    0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x96,
-    0x6d, 0x96, 0x42, 0xda, 0x64, 0x51, 0xad, 0xfa, 0x00, 0xbc, 0xbc, 0x95, 0x8a, 0xb0, 0xb9, 0x76,
-    0x01, 0xe6, 0xbd, 0xc0, 0x26, 0x79, 0x26, 0xfc, 0x0f, 0x1d, 0x87, 0x65, 0xf1, 0xf3, 0x99, 0x3a,
-    0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0x10, 0x7f, 0x77, 0xad, 0x70, 0xbd, 0x52, 0x81,
-    0x28, 0x8d, 0x24, 0x81, 0xb4, 0x3f, 0x21, 0x68, 0x9f, 0xc3, 0x80, 0x68, 0x86, 0x55, 0xfb, 0x2e,
-    0x6d, 0x96, 0xe1, 0xe1, 0xb7, 0x28, 0x8d, 0x63, 0x85, 0xba, 0x2a, 0x01, 0x33, 0x87, 0x60, 0x63,
-    0xbb, 0x16, 0x3f, 0x2f, 0x3d, 0xf4, 0x2d, 0x48, 0x5b, 0x87, 0xed, 0xda, 0x34, 0xeb, 0x9c, 0x4d,
-    0x14, 0xac, 0x65, 0xf4, 0xfa, 0xef, 0x45, 0x0b, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01,
-    0x8f, 0xa9, 0x01, 0x78, 0x28, 0x32, 0x35, 0x39, 0x34, 0x38, 0x39, 0x65, 0x36, 0x39, 0x37, 0x34,
-    0x38, 0x37, 0x30, 0x35, 0x64, 0x65, 0x33, 0x65, 0x32, 0x66, 0x34, 0x34, 0x32, 0x36, 0x37, 0x65,
-    0x61, 0x34, 0x39, 0x33, 0x38, 0x66, 0x66, 0x36, 0x61, 0x35, 0x37, 0x32, 0x35, 0x02, 0x78, 0x28,
-    0x35, 0x64, 0x34, 0x65, 0x64, 0x37, 0x66, 0x34, 0x31, 0x37, 0x61, 0x39, 0x35, 0x34, 0x61, 0x31,
-    0x38, 0x31, 0x34, 0x30, 0x37, 0x62, 0x35, 0x38, 0x38, 0x35, 0x61, 0x66, 0x64, 0x37, 0x32, 0x61,
-    0x35, 0x62, 0x66, 0x34, 0x30, 0x64, 0x61, 0x36, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 0x00,
+    0x30, 0xf7, 0x15, 0x98, 0x14, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x58, 0x1c, 0xa4, 0x3a, 0x00, 0x01,
+    0x11, 0x71, 0x63, 0x41, 0x42, 0x4c, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x01, 0x3a, 0x00, 0x01, 0x11,
+    0x73, 0xf6, 0x3a, 0x00, 0x01, 0x11, 0x74, 0x0a, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x27,
+    0xf2, 0x47, 0xaf, 0xcf, 0xd8, 0x6e, 0x5f, 0x68, 0x97, 0xa9, 0x22, 0x07, 0x81, 0xea, 0x56, 0x1f,
+    0x7b, 0x81, 0x51, 0x09, 0x8a, 0x0a, 0xab, 0x96, 0xc4, 0x4c, 0x8f, 0xf5, 0x46, 0xf4, 0xa5, 0x64,
+    0x4b, 0xed, 0x23, 0x5b, 0x9e, 0x36, 0x51, 0x1e, 0xf0, 0x1d, 0xb9, 0xcf, 0xb2, 0x4b, 0xcd, 0x52,
+    0xfa, 0x1a, 0x82, 0x11, 0x3d, 0x78, 0x1c, 0x9e, 0x0f, 0xff, 0x8a, 0x11, 0x6b, 0xdf, 0x7b, 0x3a,
+    0x00, 0x47, 0x44, 0x54, 0x58, 0x40, 0xf9, 0x00, 0x9d, 0xc2, 0x59, 0x09, 0xe0, 0xb6, 0x98, 0xbd,
+    0xe3, 0x97, 0x4a, 0xcb, 0x3c, 0xe7, 0x6b, 0x24, 0xc3, 0xe4, 0x98, 0xdd, 0xa9, 0x6a, 0x41, 0x59,
+    0x15, 0xb1, 0x23, 0xe6, 0xc8, 0xdf, 0xfb, 0x52, 0xb4, 0x52, 0xc1, 0xb9, 0x61, 0xdd, 0xbc, 0x5b,
+    0x37, 0x0e, 0x12, 0x12, 0xb2, 0xfd, 0xc1, 0x09, 0xb0, 0xcf, 0x33, 0x81, 0x4c, 0xc6, 0x29, 0x1b,
+    0x99, 0xea, 0xae, 0xfd, 0xaa, 0x0d, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47,
+    0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58,
+    0x20, 0x7f, 0x1d, 0xd1, 0xf8, 0xd3, 0xcb, 0xfe, 0xc6, 0x88, 0xa3, 0xfc, 0xa7, 0xd5, 0x34, 0xc6,
+    0x29, 0x13, 0x57, 0xfa, 0x5d, 0xc9, 0xe2, 0x1b, 0x70, 0x21, 0x48, 0x74, 0x3e, 0xa0, 0x1c, 0xe7,
+    0x31, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x3a, 0x00, 0x47, 0x44, 0x59, 0x6a, 0x61, 0x6e,
+    0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x31, 0x36, 0x58, 0x40, 0x21, 0x1f, 0xb5, 0x9b, 0x25, 0xab,
+    0xca, 0x24, 0x58, 0x7f, 0xd1, 0x9f, 0x10, 0x74, 0xbe, 0x8d, 0xbb, 0x46, 0x3e, 0xc2, 0x78, 0x2c,
+    0x28, 0x65, 0xe3, 0xd5, 0xc6, 0x11, 0x50, 0x36, 0x15, 0xfa, 0x43, 0xe5, 0xf7, 0xfd, 0x5c, 0xec,
+    0xb8, 0x96, 0xd7, 0x55, 0x51, 0x1f, 0x8e, 0xc2, 0x0b, 0x4a, 0x12, 0xe7, 0x5c, 0x3e, 0xe5, 0xaf,
+    0x19, 0xe4, 0x15, 0xf3, 0x8a, 0x58, 0x68, 0x25, 0x0e, 0x00, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0,
+    0x59, 0x01, 0xa1, 0xaa, 0x01, 0x78, 0x28, 0x34, 0x61, 0x61, 0x66, 0x61, 0x38, 0x30, 0x62, 0x30,
+    0x62, 0x30, 0x63, 0x31, 0x33, 0x34, 0x64, 0x31, 0x36, 0x65, 0x36, 0x30, 0x35, 0x36, 0x66, 0x30,
+    0x35, 0x35, 0x32, 0x62, 0x65, 0x65, 0x33, 0x38, 0x61, 0x37, 0x37, 0x30, 0x65, 0x35, 0x62, 0x02,
+    0x78, 0x28, 0x31, 0x61, 0x61, 0x32, 0x65, 0x64, 0x33, 0x63, 0x33, 0x61, 0x35, 0x36, 0x62, 0x36,
+    0x63, 0x61, 0x37, 0x35, 0x39, 0x63, 0x35, 0x32, 0x34, 0x65, 0x63, 0x38, 0x38, 0x61, 0x35, 0x37,
+    0x33, 0x30, 0x61, 0x33, 0x38, 0x61, 0x64, 0x31, 0x66, 0x36, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58,
+    0x40, 0xa4, 0x0c, 0xcb, 0xc1, 0xbf, 0xfa, 0xcc, 0xfd, 0xeb, 0xf4, 0xfc, 0x43, 0x83, 0x7f, 0x46,
+    0x8d, 0xd8, 0xd8, 0x14, 0xc1, 0x96, 0x14, 0x1f, 0x6e, 0xb3, 0xa0, 0xd9, 0x56, 0xb3, 0xbf, 0x2f,
+    0xfa, 0x88, 0x70, 0x11, 0x07, 0x39, 0xa4, 0xd2, 0xa9, 0x6b, 0x18, 0x28, 0xe8, 0x29, 0x20, 0x49,
+    0x0f, 0xbb, 0x8d, 0x08, 0x8c, 0xc6, 0x54, 0xe9, 0x71, 0xd2, 0x7e, 0xa4, 0xfe, 0x58, 0x7f, 0xd3,
+    0xc7, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x58, 0x1c, 0xa4, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x63, 0x41,
+    0x56, 0x42, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x01, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6, 0x3a, 0x00,
+    0x01, 0x11, 0x74, 0x0b, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x69, 0x3d, 0x73, 0x63, 0x70,
+    0x20, 0x41, 0xc4, 0x2d, 0x04, 0x4a, 0x4c, 0x51, 0xa9, 0x89, 0x97, 0xe4, 0x3a, 0x0f, 0x7b, 0xe2,
+    0x23, 0x5f, 0x39, 0x7e, 0xd8, 0x6f, 0x8b, 0x17, 0x04, 0x16, 0xe1, 0xb2, 0x1b, 0x5a, 0x47, 0x84,
+    0x9c, 0x54, 0x19, 0xa3, 0xb2, 0x70, 0xd3, 0xc9, 0x09, 0xf9, 0xe3, 0x3f, 0x7e, 0x19, 0xff, 0xd7,
+    0xc6, 0xa9, 0x84, 0xf1, 0xcd, 0x44, 0xec, 0x33, 0x7a, 0xa7, 0x9a, 0x3a, 0x00, 0x47, 0x44, 0x54,
+    0x58, 0x40, 0xb2, 0x69, 0x05, 0x48, 0x56, 0xb5, 0xfa, 0x55, 0x6f, 0xac, 0x56, 0xd9, 0x02, 0x35,
+    0x2b, 0xaa, 0x4c, 0xba, 0x28, 0xdd, 0x82, 0x3a, 0x86, 0xf5, 0xd4, 0xc2, 0xf1, 0xf9, 0x35, 0x7d,
+    0xe4, 0x43, 0x13, 0xbf, 0xfe, 0xd3, 0x36, 0xd8, 0x1c, 0x12, 0x78, 0x5c, 0x9c, 0x3e, 0xf6, 0x66,
+    0xef, 0xab, 0x3d, 0x0f, 0x89, 0xa4, 0x6f, 0xc9, 0x72, 0xee, 0x73, 0x43, 0x02, 0x8a, 0xef, 0xbc,
+    0x05, 0x98, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d,
+    0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x02, 0xcc, 0xfb,
+    0xac, 0x73, 0xee, 0xf7, 0x46, 0x04, 0xa2, 0x9e, 0x32, 0xac, 0xa1, 0xf8, 0x7a, 0x08, 0x83, 0xec,
+    0xfb, 0x82, 0x13, 0xce, 0x4a, 0xed, 0x55, 0x52, 0x24, 0x36, 0x67, 0xe8, 0x45, 0x3a, 0x00, 0x47,
+    0x44, 0x58, 0x41, 0x20, 0x3a, 0x00, 0x47, 0x44, 0x59, 0x6a, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+    0x64, 0x2e, 0x31, 0x36, 0x58, 0x40, 0xb8, 0x67, 0x7a, 0x4e, 0x89, 0xe4, 0x73, 0xc3, 0xa4, 0x5d,
+    0x30, 0xea, 0xd4, 0x53, 0x51, 0x15, 0xc2, 0x26, 0x4d, 0xae, 0xeb, 0x94, 0x00, 0x92, 0x9e, 0x05,
+    0x23, 0x8b, 0xde, 0x4b, 0x56, 0x72, 0x33, 0x2c, 0xf4, 0xf7, 0x81, 0x09, 0xce, 0xf4, 0x41, 0x7a,
+    0xa4, 0xc6, 0x4e, 0x3a, 0x0b, 0xb3, 0x5a, 0x70, 0x72, 0x9e, 0x41, 0xe3, 0x25, 0x41, 0x9e, 0x77,
+    0x6d, 0x44, 0x9a, 0x63, 0xc9, 0x0f, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0xa5, 0xaa,
+    0x01, 0x78, 0x28, 0x31, 0x61, 0x61, 0x32, 0x65, 0x64, 0x33, 0x63, 0x33, 0x61, 0x35, 0x36, 0x62,
+    0x36, 0x63, 0x61, 0x37, 0x35, 0x39, 0x63, 0x35, 0x32, 0x34, 0x65, 0x63, 0x38, 0x38, 0x61, 0x35,
+    0x37, 0x33, 0x30, 0x61, 0x33, 0x38, 0x61, 0x64, 0x31, 0x66, 0x36, 0x02, 0x78, 0x28, 0x36, 0x61,
+    0x38, 0x38, 0x61, 0x31, 0x62, 0x34, 0x31, 0x35, 0x39, 0x35, 0x66, 0x37, 0x66, 0x36, 0x31, 0x39,
+    0x35, 0x34, 0x31, 0x65, 0x39, 0x33, 0x39, 0x38, 0x31, 0x36, 0x64, 0x35, 0x39, 0x62, 0x32, 0x61,
+    0x37, 0x62, 0x61, 0x33, 0x31, 0x31, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a,
-    0x00, 0x47, 0x44, 0x53, 0x58, 0x1a, 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x67, 0x41, 0x6e, 0x64,
-    0x72, 0x6f, 0x69, 0x64, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x0c, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6,
-    0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x26, 0x1a, 0xbd, 0x26, 0xd8, 0x37, 0x8f, 0x4a, 0xf2,
-    0x9e, 0x49, 0x4d, 0x93, 0x23, 0xc4, 0x6e, 0x02, 0xda, 0xe0, 0x00, 0x02, 0xe7, 0xed, 0x29, 0xdf,
-    0x2b, 0xb3, 0x69, 0xf3, 0x55, 0x0e, 0x4c, 0x22, 0xdc, 0xcf, 0xf5, 0x92, 0xc9, 0xfa, 0x78, 0x98,
-    0xf1, 0x0e, 0x55, 0x5f, 0xf4, 0x45, 0xed, 0xc0, 0x0a, 0x72, 0x2a, 0x7a, 0x3a, 0xd2, 0xb1, 0xf7,
-    0x76, 0xfe, 0x2a, 0x6b, 0x7b, 0x2a, 0x53, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x40, 0x04, 0x25,
-    0x5d, 0x60, 0x5f, 0x5c, 0x45, 0x0d, 0xf2, 0x9a, 0x6e, 0x99, 0x30, 0x03, 0xb8, 0xd6, 0xe1, 0x99,
-    0x71, 0x1b, 0xf8, 0x44, 0xfa, 0xb5, 0x31, 0x79, 0x1c, 0x37, 0x68, 0x4e, 0x1d, 0xc0, 0x24, 0x74,
-    0x68, 0xf8, 0x80, 0x20, 0x3e, 0x44, 0xb1, 0x43, 0xd2, 0x9c, 0xfc, 0x12, 0x9e, 0x77, 0x0a, 0xde,
-    0x29, 0x24, 0xff, 0x2e, 0xfa, 0xc7, 0x10, 0xd5, 0x73, 0xd4, 0xc6, 0xdf, 0x62, 0x9f, 0x3a, 0x00,
-    0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03,
-    0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0xdb, 0xe7, 0x5b, 0x3f, 0xa3, 0x42, 0xb0,
-    0x9c, 0xf8, 0x40, 0x8c, 0xb0, 0x9c, 0xf0, 0x0a, 0xaf, 0xdf, 0x6f, 0xe5, 0x09, 0x21, 0x11, 0x92,
-    0xe1, 0xf8, 0xc5, 0x09, 0x02, 0x3d, 0x1f, 0xb7, 0xc5, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20,
-    0x58, 0x40, 0xc4, 0xc1, 0xd7, 0x1c, 0x2d, 0x26, 0x89, 0x22, 0xcf, 0xa6, 0x99, 0x77, 0x30, 0x84,
-    0x86, 0x27, 0x59, 0x8f, 0xd8, 0x08, 0x75, 0xe0, 0xb2, 0xef, 0xf9, 0xfa, 0xa5, 0x40, 0x8c, 0xd3,
-    0xeb, 0xbb, 0xda, 0xf2, 0xc8, 0xae, 0x41, 0x22, 0x50, 0x9c, 0xe8, 0xb2, 0x9c, 0x9b, 0x3f, 0x8a,
-    0x78, 0x76, 0xab, 0xd0, 0xbe, 0xfc, 0xe4, 0x79, 0xcb, 0x1b, 0x2b, 0xaa, 0x4d, 0xdd, 0x15, 0x61,
-    0x42, 0x06,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x47,
+    0x44, 0x53, 0x58, 0x20, 0xa4, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x67, 0x41, 0x6e, 0x64, 0x72, 0x6f,
+    0x69, 0x64, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x0c, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6, 0x3a, 0x00,
+    0x01, 0x11, 0x74, 0x0c, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0xd7, 0x67, 0x6d, 0x47, 0xf1,
+    0x17, 0xf6, 0x16, 0x58, 0x80, 0x5e, 0x40, 0x92, 0x35, 0x8d, 0xc6, 0x9a, 0x0d, 0x71, 0xe0, 0x56,
+    0x33, 0x0e, 0xad, 0x95, 0xf3, 0xd9, 0xa5, 0x44, 0x90, 0x2b, 0xa0, 0x73, 0xa0, 0xf8, 0x17, 0x9b,
+    0x2a, 0xdc, 0xa4, 0x42, 0xdf, 0x8c, 0xfc, 0x32, 0x19, 0x92, 0x66, 0x75, 0x90, 0x88, 0x85, 0x5d,
+    0x89, 0x5a, 0xb1, 0xdc, 0x95, 0xc9, 0x84, 0x68, 0x3f, 0x35, 0xe4, 0x3a, 0x00, 0x47, 0x44, 0x54,
+    0x58, 0x40, 0x04, 0x25, 0x5d, 0x60, 0x5f, 0x5c, 0x45, 0x0d, 0xf2, 0x9a, 0x6e, 0x99, 0x30, 0x03,
+    0xb8, 0xd6, 0xe1, 0x99, 0x71, 0x1b, 0xf8, 0x44, 0xfa, 0xb5, 0x31, 0x79, 0x1c, 0x37, 0x68, 0x4e,
+    0x1d, 0xc0, 0x24, 0x74, 0x68, 0xf8, 0x80, 0x20, 0x3e, 0x44, 0xb1, 0x43, 0xd2, 0x9c, 0xfc, 0x12,
+    0x9e, 0x77, 0x0a, 0xde, 0x29, 0x24, 0xff, 0x2e, 0xfa, 0xc7, 0x10, 0xd5, 0x73, 0xd4, 0xc6, 0xdf,
+    0x62, 0x9f, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d,
+    0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x45, 0xc7, 0x2d,
+    0x68, 0x01, 0x96, 0x6d, 0xaf, 0x0a, 0xcd, 0x51, 0x56, 0xfb, 0xac, 0x27, 0xa1, 0x61, 0x59, 0x9b,
+    0xfd, 0xb4, 0x86, 0x73, 0x20, 0x65, 0x64, 0x3c, 0x77, 0xf1, 0x7b, 0x1d, 0x4d, 0x3a, 0x00, 0x47,
+    0x44, 0x58, 0x41, 0x20, 0x3a, 0x00, 0x47, 0x44, 0x59, 0x6a, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+    0x64, 0x2e, 0x31, 0x36, 0x58, 0x40, 0xa5, 0xf8, 0xfe, 0x9d, 0x8c, 0xda, 0x71, 0x0c, 0x51, 0x99,
+    0xe5, 0x48, 0xd3, 0x03, 0xb4, 0x96, 0x67, 0xab, 0xf7, 0x82, 0xf5, 0x70, 0x2b, 0x17, 0xe4, 0x02,
+    0xa1, 0x3c, 0xbc, 0x7c, 0x63, 0x79, 0x0b, 0x01, 0x0c, 0x92, 0x13, 0x39, 0xb2, 0xc8, 0x0e, 0x0c,
+    0x09, 0x90, 0xb9, 0x19, 0x9b, 0x3b, 0xc3, 0x12, 0x9c, 0xea, 0xf6, 0xcb, 0x84, 0x14, 0xf0, 0xcb,
+    0xa5, 0x05, 0x58, 0x3d, 0x45, 0x03,
 ];
 const MESSAGE: &[u8] = b"Message for testing";
 
diff --git a/tests/early_vm_test/Android.bp b/tests/early_vm_test/Android.bp
new file mode 100644
index 0000000..dbb0c28
--- /dev/null
+++ b/tests/early_vm_test/Android.bp
@@ -0,0 +1,53 @@
+prebuilt_etc {
+    name: "avf_early_vm_test_kernel",
+    filename: "rialto.bin",
+    src: ":empty_file",
+    target: {
+        android_arm64: {
+            src: ":rialto_signed",
+        },
+    },
+    installable: false,
+    system_ext_specific: true,
+    visibility: ["//visibility:private"],
+}
+
+rust_binary {
+    name: "avf_early_vm_test_launcher",
+    crate_name: "avf_early_vm_test_launcher",
+    srcs: ["src/main.rs"],
+    rustlibs: [
+        "android.system.virtualizationservice-rust",
+        "libanyhow",
+        "libclap",
+        "libhypervisor_props",
+        "liblog_rust",
+        "libservice_vm_comm",
+        "libservice_vm_manager",
+        "libvmclient",
+    ],
+    cfgs: select(release_flag("RELEASE_AVF_ENABLE_EARLY_VM"), {
+        true: ["early_vm_enabled"],
+        default: [],
+    }),
+    prefer_rlib: true,
+    system_ext_specific: true,
+    compile_multilib: "first",
+    installable: false,
+}
+
+python_test_host {
+    name: "avf_early_vm_test",
+    main: "avf_early_vm_test.py",
+    srcs: ["avf_early_vm_test.py"],
+    device_first_data: [
+        ":avf_early_vm_test_kernel",
+        ":avf_early_vm_test_launcher",
+    ],
+    data: ["early_vms_rialto_test.xml"],
+    test_suites: ["general-tests"],
+    test_config: "AndroidTest.xml",
+    test_options: {
+        unit_test: false,
+    },
+}
diff --git a/tests/early_vm_test/AndroidTest.xml b/tests/early_vm_test/AndroidTest.xml
new file mode 100644
index 0000000..3eae96d
--- /dev/null
+++ b/tests/early_vm_test/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<configuration description="Runs avf_early_vm_test.">
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+        <option name="force-root" value="true"/>
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+    <option name="abort-on-push-failure" value="true" />
+        <option name="remount-system" value="true" />
+        <option name="push-file" key="avf_early_vm_test_launcher" value="/system_ext/bin/avf_early_vm_test_launcher" />
+        <option name="push-file" key="rialto.bin" value="/system_ext/etc/avf/rialto_test.bin" />
+        <option name="push-file" key="early_vms_rialto_test.xml" value="/system_ext/etc/avf/early_vms_rialto_test.xml" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.python.PythonBinaryHostTest">
+        <option name="par-file-name" value="avf_early_vm_test" />
+        <option name="test-timeout" value="5m" />
+    </test>
+</configuration>
diff --git a/tests/early_vm_test/TEST_MAPPING b/tests/early_vm_test/TEST_MAPPING
new file mode 100644
index 0000000..1f2335b
--- /dev/null
+++ b/tests/early_vm_test/TEST_MAPPING
@@ -0,0 +1,9 @@
+// When adding or removing tests here, don't forget to amend _all_modules list in
+// wireless/android/busytown/ath_config/configs/prod/avf/tests.gcl
+{
+  "avf-presubmit": [
+    {
+      "name": "avf_early_vm_test"
+    }
+  ]
+}
diff --git a/tests/early_vm_test/avf_early_vm_test.py b/tests/early_vm_test/avf_early_vm_test.py
new file mode 100644
index 0000000..0003351
--- /dev/null
+++ b/tests/early_vm_test/avf_early_vm_test.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+#
+# Copyright 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.
+#
+
+import logging
+import os
+import subprocess
+import unittest
+
+_DEFAULT_COMMAND_TIMEOUT = 300
+_LAUNCHER_PATH = "/system_ext/bin/avf_early_vm_test_launcher"
+_RIALTO_PATH = "/system_ext/etc/avf/rialto_test.bin"
+
+def _RunCommand(cmd, timeout=_DEFAULT_COMMAND_TIMEOUT):
+    with subprocess.Popen(args=cmd,
+                          stderr=subprocess.PIPE,
+                          stdout=subprocess.PIPE,
+                          universal_newlines=True) as proc:
+        try:
+            out, err = proc.communicate(timeout=timeout)
+            returncode = proc.returncode
+        except subprocess.TimeoutExpired:
+            proc.kill()
+            out, err = proc.communicate()
+            returncode = proc.returncode
+
+    return out, err, returncode
+
+class AvfEarlyVmTest(unittest.TestCase):
+    def setUp(self):
+        self._serial_number = os.environ.get("ANDROID_SERIAL")
+        self.assertTrue(self._serial_number, "$ANDROID_SERIAL is empty.")
+
+    def _TestAvfEarlyVm(self, protected):
+        adb_cmd = ["adb", "-s", self._serial_number, "shell", _LAUNCHER_PATH, "--kernel",
+                   _RIALTO_PATH]
+        if protected:
+            adb_cmd.append("--protected")
+
+        _, err, returncode = _RunCommand(adb_cmd)
+        self.assertEqual(returncode, 0, f"{adb_cmd} failed: {err}")
+
+    def testAvfEarlyVmNonProtected(self):
+        self._TestAvfEarlyVm(False)
+
+    def testAvfEarlyVmProtected(self):
+        self._TestAvfEarlyVm(True)
+
+if __name__ == "__main__":
+    # Setting verbosity is required to generate output that the TradeFed test
+    # runner can parse.
+    unittest.main(verbosity=3)
diff --git a/tests/early_vm_test/early_vms_rialto_test.xml b/tests/early_vm_test/early_vms_rialto_test.xml
new file mode 100644
index 0000000..799fc3f
--- /dev/null
+++ b/tests/early_vm_test/early_vms_rialto_test.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<early_vms>
+    <early_vm>
+        <name>avf_early_vm_test_launcher</name>
+        <cid>299</cid>
+        <path>/system_ext/bin/avf_early_vm_test_launcher</path>
+    </early_vm>
+</early_vms>
diff --git a/tests/early_vm_test/src/main.rs b/tests/early_vm_test/src/main.rs
new file mode 100644
index 0000000..a3c80ca
--- /dev/null
+++ b/tests/early_vm_test/src/main.rs
@@ -0,0 +1,116 @@
+// Copyright 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.
+
+//! Tests running an early VM
+
+use android_system_virtualizationservice::{
+    aidl::android::system::virtualizationservice::{
+        IVirtualizationService::IVirtualizationService, VirtualMachineConfig::VirtualMachineConfig,
+        VirtualMachineRawConfig::VirtualMachineRawConfig,
+    },
+    binder::{ParcelFileDescriptor, ProcessState, Strong},
+};
+use anyhow::{Context, Result};
+use clap::Parser;
+use log::info;
+use std::fs::File;
+use std::path::PathBuf;
+
+use service_vm_comm::{Request, Response, VmType};
+use service_vm_manager::ServiceVm;
+use vmclient::VmInstance;
+
+const VM_MEMORY_MB: i32 = 16;
+
+#[derive(Parser)]
+/// Collection of CLI for avf_early_vm_test_rialto
+pub struct Args {
+    /// Path to the Rialto kernel image.
+    #[arg(long)]
+    kernel: PathBuf,
+
+    /// Whether the VM is protected or not.
+    #[arg(long)]
+    protected: bool,
+}
+
+fn get_service() -> Result<Strong<dyn IVirtualizationService>> {
+    let virtmgr = vmclient::VirtualizationService::new_early()
+        .context("Failed to spawn VirtualizationService")?;
+    virtmgr.connect().context("Failed to connect to VirtualizationService")
+}
+
+fn main() -> Result<()> {
+    if std::env::consts::ARCH != "aarch64" {
+        info!("{} not supported. skipping test", std::env::consts::ARCH);
+        return Ok(());
+    }
+
+    if !cfg!(early_vm_enabled) {
+        info!("early VM disabled. skipping test");
+        return Ok(());
+    }
+
+    let args = Args::parse();
+
+    if args.protected {
+        if !hypervisor_props::is_protected_vm_supported()? {
+            info!("pVMs are not supported on device. skipping test");
+            return Ok(());
+        }
+    } else if !hypervisor_props::is_vm_supported()? {
+        info!("non-pVMs are not supported on device. skipping test");
+        return Ok(());
+    }
+
+    let service = get_service()?;
+    let kernel =
+        File::open(&args.kernel).with_context(|| format!("Failed to open {:?}", &args.kernel))?;
+    let kernel = ParcelFileDescriptor::new(kernel);
+
+    let vm_config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
+        name: "avf_early_vm_test_launcher".to_owned(),
+        kernel: Some(kernel),
+        protectedVm: args.protected,
+        memoryMib: VM_MEMORY_MB,
+        platformVersion: "~1.0".to_owned(),
+        ..Default::default()
+    });
+
+    let vm_instance = VmInstance::create(
+        service.as_ref(),
+        &vm_config,
+        // console_in, console_out, and log will be redirected to the kernel log by virtmgr
+        None, // console_in
+        None, // console_out
+        None, // log
+        None, // dump_dt
+        None, // callback
+    )
+    .context("Failed to create VM")?;
+
+    ProcessState::start_thread_pool();
+
+    let vm_type = if args.protected { VmType::ProtectedVm } else { VmType::NonProtectedVm };
+    let mut vm_service = ServiceVm::start_vm(vm_instance, vm_type)?;
+
+    let request_data = vec![1, 2, 3, 4, 5];
+    let reversed_data = vec![5, 4, 3, 2, 1];
+    let response = vm_service
+        .process_request(Request::Reverse(request_data))
+        .context("Failed to process request")?;
+    assert_eq!(Response::Reverse(reversed_data), response);
+
+    Ok(())
+}
diff --git a/tests/hostside/Android.bp b/tests/hostside/Android.bp
index 0966c20..6d7c25e 100644
--- a/tests/hostside/Android.bp
+++ b/tests/hostside/Android.bp
@@ -59,7 +59,8 @@
 java_test_host {
     name: "MicrodroidHostTestCases",
     defaults: ["MicrodroidHostTestCases.default"],
-    test_config: "AndroidTest.xml",
+    test_config_template: "AndroidTestTemplate.xml",
+    auto_gen_config: true,
     test_suites: [
         "general-tests",
         "pts",
@@ -71,8 +72,21 @@
 java_test_host {
     name: "MicrodroidHostTestCases.CTS",
     defaults: ["MicrodroidHostTestCases.default"],
-    test_config: ":MicrodroidHostTestCases.CTS.config",
+    test_config_template: "AndroidTestTemplate.xml",
     test_suites: ["cts"],
+    auto_gen_config: true,
+    test_options: {
+        tradefed_options: [
+            {
+                name: "include-annotation",
+                value: "com.android.compatibility.common.util.CddTest",
+            },
+            {
+                name: "test-suite-tag",
+                value: "cts",
+            },
+        ],
+    },
     device_common_data: DEVICE_DATA,
     data_native_bins: BINS,
 }
@@ -80,30 +94,43 @@
 java_test_host {
     name: "MicrodroidHostTestCases.VTS",
     defaults: ["MicrodroidHostTestCases.default"],
-    test_config: ":MicrodroidHostTestCases.VTS.config",
+    test_config_template: "AndroidTestTemplate.xml",
     test_suites: ["vts"],
+    auto_gen_config: true,
+    test_options: {
+        tradefed_options: [
+            {
+                name: "include-annotation",
+                value: "com.android.compatibility.common.util.VsrTest",
+            },
+            {
+                name: "test-suite-tag",
+                value: "vts",
+            },
+        ],
+    },
     device_common_data: DEVICE_DATA,
     data_native_bins: BINS,
 }
 
-genrule {
-    name: "MicrodroidHostTestCases.CTS.config",
-    srcs: ["AndroidTest.xml"],
-    out: ["out.xml"],
-    cmd: "sed " +
-        "-e 's/<!-- PLACEHOLDER_FOR_ANNOTATION -->/" +
-        "<option name=\"include-annotation\" value=\"com.android.compatibility.common.util.CddTest\" \\/>/' " +
-        "-e 's/MicrodroidHostTestCases.jar/MicrodroidHostTestCases.CTS.jar/' " +
-        "$(in) > $(out)",
-}
-
-genrule {
-    name: "MicrodroidHostTestCases.VTS.config",
-    srcs: ["AndroidTest.xml"],
-    out: ["out.xml"],
-    cmd: "sed " +
-        "-e 's/<!-- PLACEHOLDER_FOR_ANNOTATION -->/" +
-        "<option name=\"include-annotation\" value=\"com.android.compatibility.common.util.VsrTest\" \\/>/' " +
-        "-e 's/MicrodroidHostTestCases.jar/MicrodroidHostTestCases.VTS.jar/' " +
-        "$(in) > $(out)",
+java_test_host {
+    name: "MicrodroidHostTestCases.GTS",
+    defaults: ["MicrodroidHostTestCases.default"],
+    test_config_template: "AndroidTestTemplate.xml",
+    test_suites: ["gts"],
+    auto_gen_config: true,
+    test_options: {
+        tradefed_options: [
+            {
+                name: "include-annotation",
+                value: "com.android.compatibility.common.util.GmsTest",
+            },
+            {
+                name: "test-suite-tag",
+                value: "gts",
+            },
+        ],
+    },
+    device_common_data: DEVICE_DATA,
+    data_native_bins: BINS,
 }
diff --git a/tests/hostside/AndroidTest.xml b/tests/hostside/AndroidTestTemplate.xml
similarity index 91%
rename from tests/hostside/AndroidTest.xml
rename to tests/hostside/AndroidTestTemplate.xml
index c277865..ac066bc 100644
--- a/tests/hostside/AndroidTest.xml
+++ b/tests/hostside/AndroidTestTemplate.xml
@@ -14,7 +14,6 @@
      limitations under the License.
 -->
 <configuration description="Host driven tests for Microdroid">
-    <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="security" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
@@ -26,12 +25,12 @@
     </target_preparer>
 
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
-        <option name="jar" value="MicrodroidHostTestCases.jar" />
+        <option name="jar" value="{MODULE}.jar" />
     </test>
 
     <!-- Controller that will skip the module if a native bridge situation is detected -->
     <!-- For example: module wants to run arm and device is x86 -->
     <object type="module_controller" class="com.android.tradefed.testtype.suite.module.NativeBridgeModuleController" />
 
-    <!-- PLACEHOLDER_FOR_ANNOTATION -->
+    {EXTRA_CONFIGS}
 </configuration>
diff --git a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
index 01ac6a1..4f9806a 100644
--- a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
+++ b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
@@ -36,6 +36,7 @@
 import android.cts.statsdatom.lib.ReportUtils;
 
 import com.android.compatibility.common.util.CddTest;
+import com.android.compatibility.common.util.GmsTest;
 import com.android.compatibility.common.util.PropertyUtil;
 import com.android.compatibility.common.util.VsrTest;
 import com.android.microdroid.test.common.ProcessUtil;
@@ -415,7 +416,8 @@
 
     @Test
     @CddTest
-    @VsrTest(requirements = {"VSR-7.1-001.008"})
+    @GmsTest(requirements = {"GMS-3-7.1-002", "GMS-VSR-7.1-001.006"})
+    @VsrTest(requirements = {"VSR-7.1-001.007"})
     public void UpgradedPackageIsAcceptedWithSecretkeeper() throws Exception {
         // Preconditions
         assumeVmTypeSupported("microdroid", true); // Non-protected VMs may not support upgrades
@@ -433,7 +435,8 @@
 
     @Test
     @CddTest
-    @VsrTest(requirements = {"VSR-7.1-001.008"})
+    @GmsTest(requirements = {"GMS-3-7.1-002", "GMS-VSR-7.1-001.006"})
+    @VsrTest(requirements = {"VSR-7.1-001.007"})
     public void DowngradedPackageIsRejectedProtectedVm() throws Exception {
         // Preconditions: Rollback protection is provided only for protected VM.
         assumeVmTypeSupported("microdroid", true);
@@ -482,7 +485,7 @@
     @Test
     @Parameters(method = "osVersions")
     @TestCaseName("{method}_os_{0}")
-    @CddTest(requirements = {"9.17/C-2-1", "9.17/C-2-2", "9.17/C-2-6"})
+    @GmsTest(requirements = {"GMS-3-7.1-010"})
     public void protectedVmRunsPvmfw(String os) throws Exception {
         // Arrange
         assumeKernelSupported(os);
@@ -515,7 +518,7 @@
     @Test
     @Parameters(method = "osVersions")
     @TestCaseName("{method}_os_{0}")
-    @CddTest(requirements = {"9.17/C-2-1", "9.17/C-2-2", "9.17/C-2-5", "9.17/C-2-6"})
+    @GmsTest(requirements = {"GMS-3-7.1-003", "GMS-3-7.1-010"})
     public void protectedVmWithImageSignedWithDifferentKeyFailsToVerifyPayload(String os)
             throws Exception {
         assumeKernelSupported(os);
@@ -544,7 +547,7 @@
     @Test
     @Parameters(method = "osVersions")
     @TestCaseName("{method}_os_{0}")
-    @CddTest(requirements = {"9.17/C-2-2", "9.17/C-2-6"})
+    @GmsTest(requirements = {"GMS-3-7.1-003", "GMS-3-7.1-010"})
     public void testBootSucceedsWhenNonProtectedVmStartsWithImagesSignedWithDifferentKey(String os)
             throws Exception {
         // Preconditions
@@ -572,7 +575,7 @@
     @Test
     @Parameters(method = "osVersions")
     @TestCaseName("{method}_os_{0}")
-    @CddTest(requirements = {"9.17/C-2-2", "9.17/C-2-5", "9.17/C-2-6"})
+    @GmsTest(requirements = {"GMS-3-7.1-006"})
     public void testBootFailsWhenVbMetaDigestDoesNotMatchBootconfig(String os) throws Exception {
         // protectedVmWithImageSignedWithDifferentKeyRunsPvmfw() is the protected case.
         assumeKernelSupported(os);
@@ -1010,7 +1013,8 @@
     @Test
     @Parameters(method = "params")
     @TestCaseName("{method}_protectedVm_{0}_os_{1}")
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-1-2", "9.17/C/1-3"})
+    @CddTest
+    @GmsTest(requirements = {"GMS-3-7.1-001.002"})
     public void testMicrodroidBoots(boolean protectedVm, String os) throws Exception {
         // Preconditions
         assumeKernelSupported(os);
@@ -1097,6 +1101,7 @@
     }
 
     @Test
+    @CddTest
     public void testPathToBinaryIsRejected() throws Exception {
         CommandRunner android = new CommandRunner(getDevice());
 
@@ -1145,6 +1150,7 @@
     }
 
     @Test
+    @CddTest
     public void testRunEmptyPayload() throws Exception {
         CommandRunner android = new CommandRunner(getDevice());
 
@@ -1198,7 +1204,6 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-2-2", "9.17/C-2-6"})
     public void testAllVbmetaUseSHA256() throws Exception {
         File virtApexDir = FileUtil.createTempDir("virt_apex");
         // Pull the virt apex's etc/ directory (which contains images)
@@ -1309,6 +1314,7 @@
     @Test
     @Parameters(method = "params")
     @TestCaseName("{method}_protectedVm_{0}_os_{1}")
+    @CddTest
     public void testDeviceAssignment(boolean protectedVm, String os) throws Exception {
         // Preconditions
         assumeKernelSupported(os);
@@ -1364,6 +1370,8 @@
     }
 
     @Test
+    @CddTest
+    @GmsTest(requirements = {"GMS-3-7.1-001.002"})
     public void testOsVersions() throws Exception {
         for (String os : getSupportedOSList()) {
             assertWithMessage("Unknown OS \"%s\"", os).that(SUPPORTED_OSES.values()).contains(os);
@@ -1414,6 +1422,7 @@
     @Test
     @Parameters(method = "osVersions")
     @TestCaseName("{method}_os_{0}")
+    @CddTest
     public void microdroidDeviceTreeCompat(String os) throws Exception {
         assumeArm64Supported();
         final String configPath = "assets/vm_config.json";
@@ -1442,6 +1451,7 @@
     @Test
     @Parameters(method = "osVersions")
     @TestCaseName("{method}_os_{0}")
+    @CddTest
     public void microdroidProtectedDeviceTreeCompat(String os) throws Exception {
         assumeArm64Supported();
         final String configPath = "assets/vm_config.json";
diff --git a/tests/testapk/Android.bp b/tests/testapk/Android.bp
index 8a95fe9..d0e045b 100644
--- a/tests/testapk/Android.bp
+++ b/tests/testapk/Android.bp
@@ -73,7 +73,8 @@
     defaults: ["MicrodroidVersionsTestAppDefaults"],
     manifest: "AndroidManifestV5.xml",
     test_suites: ["general-tests"],
-    test_config: "AndroidTest.xml",
+    test_config_template: "AndroidTestTemplate.xml",
+    auto_gen_config: true,
     data: DATA,
 }
 
@@ -81,8 +82,21 @@
     name: "MicrodroidTestApp.CTS",
     defaults: ["MicrodroidVersionsTestAppDefaults"],
     manifest: "AndroidManifestV5.xml",
+    test_config_template: "AndroidTestTemplate.xml",
     test_suites: ["cts"],
-    test_config: ":MicrodroidTestApp.CTS.config",
+    auto_gen_config: true,
+    test_options: {
+        tradefed_options: [
+            {
+                name: "include-annotation",
+                value: "com.android.compatibility.common.util.CddTest",
+            },
+            {
+                name: "test-suite-tag",
+                value: "cts",
+            },
+        ],
+    },
     data: DATA,
 }
 
@@ -90,31 +104,44 @@
     name: "MicrodroidTestApp.VTS",
     defaults: ["MicrodroidVersionsTestAppDefaults"],
     manifest: "AndroidManifestV5.xml",
+    test_config_template: "AndroidTestTemplate.xml",
     test_suites: ["vts"],
-    test_config: ":MicrodroidTestApp.VTS.config",
+    auto_gen_config: true,
+    test_options: {
+        tradefed_options: [
+            {
+                name: "include-annotation",
+                value: "com.android.compatibility.common.util.VsrTest",
+            },
+            {
+                name: "test-suite-tag",
+                value: "vts",
+            },
+        ],
+    },
     data: DATA,
 }
 
-genrule {
-    name: "MicrodroidTestApp.CTS.config",
-    srcs: ["AndroidTest.xml"],
-    out: ["out.xml"],
-    cmd: "sed " +
-        "-e 's/<!-- PLACEHOLDER_FOR_ANNOTATION -->/" +
-        "<option name=\"include-annotation\" value=\"com.android.compatibility.common.util.CddTest\" \\/>/' " +
-        "-e 's/MicrodroidTestApp.apk/MicrodroidTestApp.CTS.apk/' " +
-        "$(in) > $(out)",
-}
-
-genrule {
-    name: "MicrodroidTestApp.VTS.config",
-    srcs: ["AndroidTest.xml"],
-    out: ["out.xml"],
-    cmd: "sed " +
-        "-e 's/<!-- PLACEHOLDER_FOR_ANNOTATION -->/" +
-        "<option name=\"include-annotation\" value=\"com.android.compatibility.common.util.VsrTest\" \\/>/' " +
-        "-e 's/MicrodroidTestApp.apk/MicrodroidTestApp.VTS.apk/' " +
-        "$(in) > $(out)",
+android_test {
+    name: "MicrodroidTestApp.GTS",
+    defaults: ["MicrodroidVersionsTestAppDefaults"],
+    manifest: "AndroidManifestV5.xml",
+    test_config_template: "AndroidTestTemplate.xml",
+    test_suites: ["gts"],
+    auto_gen_config: true,
+    test_options: {
+        tradefed_options: [
+            {
+                name: "include-annotation",
+                value: "com.android.compatibility.common.util.GmsTest",
+            },
+            {
+                name: "test-suite-tag",
+                value: "gts",
+            },
+        ],
+    },
+    data: DATA,
 }
 
 android_test_helper_app {
diff --git a/tests/testapk/AndroidTest.xml b/tests/testapk/AndroidTestTemplate.xml
similarity index 92%
rename from tests/testapk/AndroidTest.xml
rename to tests/testapk/AndroidTestTemplate.xml
index 221c25c..613ce28 100644
--- a/tests/testapk/AndroidTest.xml
+++ b/tests/testapk/AndroidTestTemplate.xml
@@ -14,14 +14,12 @@
      limitations under the License.
 -->
 <configuration description="Runs Microdroid device-side tests.">
-    <option name="test-suite-tag" value="cts" />
-    <option name="test-suite-tag" value="vts" />
     <option name="config-descriptor:metadata" key="component" value="security" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
-        <option name="test-file-name" value="MicrodroidTestApp.apk" />
+        <option name="test-file-name" value="{MODULE}.apk" />
         <option name="test-file-name" value="MicrodroidVmShareApp.apk" />
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
@@ -44,5 +42,5 @@
     <!-- For example: module wants to run arm and device is x86 -->
     <object type="module_controller" class="com.android.tradefed.testtype.suite.module.NativeBridgeModuleController" />
 
-    <!-- PLACEHOLDER_FOR_ANNOTATION -->
+    {EXTRA_CONFIGS}
 </configuration>
diff --git a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidCapabilitiesTest.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidCapabilitiesTest.java
index 08bc310..df5525f 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidCapabilitiesTest.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidCapabilitiesTest.java
@@ -40,7 +40,7 @@
 @RunWith(JUnit4.class)
 public class MicrodroidCapabilitiesTest extends MicrodroidDeviceTestBase {
     @Test
-    @CddTest(requirements = "9.17/C-1-6")
+    @CddTest(requirements = "9.17/C-1-1")
     public void supportForProtectedOrNonProtectedVms() {
         assumeSupportedDevice();
 
@@ -61,7 +61,7 @@
     }
 
     @Test
-    @VsrTest(requirements = "VSR-7.1-001.005")
+    @VsrTest(requirements = "VSR-7.1-001.004")
     public void avfIsRequired() {
         assumeVsrCompliant();
         assume().withMessage("Requirement doesn't apply due to vendor API level")
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 9c66765..6260458 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -66,6 +66,7 @@
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.CddTest;
+import com.android.compatibility.common.util.GmsTest;
 import com.android.compatibility.common.util.VsrTest;
 import com.android.microdroid.test.device.MicrodroidDeviceTestBase;
 import com.android.microdroid.test.vmshare.IVmShareTestService;
@@ -216,13 +217,13 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+    @CddTest
     public void createAndConnectToVm() throws Exception {
         createAndConnectToVmHelper(CPU_TOPOLOGY_ONE_CPU, /* shouldUseHugepages= */ false);
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+    @CddTest
     public void createAndConnectToVm_HostCpuTopology() throws Exception {
         createAndConnectToVmHelper(CPU_TOPOLOGY_MATCH_HOST, /* shouldUseHugepages= */ false);
     }
@@ -248,8 +249,9 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+    @CddTest
     @VsrTest(requirements = {"VSR-7.1-001.006"})
+    @GmsTest(requirements = {"GMS-VSR-7.1-001.005"})
     public void vmAttestationWhenRemoteAttestationIsNotSupported() throws Exception {
         // pVM remote attestation is only supported on protected VMs.
         assumeProtectedVM();
@@ -276,8 +278,9 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+    @CddTest
     @VsrTest(requirements = {"VSR-7.1-001.006"})
+    @GmsTest(requirements = {"GMS-VSR-7.1-001.005"})
     public void vmAttestationWithVendorPartitionWhenSupported() throws Exception {
         // pVM remote attestation is only supported on protected VMs.
         assumeProtectedVM();
@@ -294,8 +297,9 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+    @CddTest
     @VsrTest(requirements = {"VSR-7.1-001.006"})
+    @GmsTest(requirements = {"GMS-VSR-7.1-001.005"})
     public void vmAttestationWhenRemoteAttestationIsSupported() throws Exception {
         // pVM remote attestation is only supported on protected VMs.
         assumeProtectedVM();
@@ -340,7 +344,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+    @CddTest
     public void createAndRunNoDebugVm() throws Exception {
         assumeSupportedDevice();
 
@@ -361,7 +365,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void autoCloseVm() throws Exception {
         assumeSupportedDevice();
 
@@ -391,7 +395,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void autoCloseVmDescriptor() throws Exception {
         VirtualMachineConfig config =
                 newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
@@ -420,7 +424,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void vmDescriptorClosedOnImport() throws Exception {
         VirtualMachineConfig config =
                 newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
@@ -443,7 +447,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void vmLifecycleChecks() throws Exception {
         assumeSupportedDevice();
 
@@ -491,7 +495,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void connectVsock() throws Exception {
         assumeSupportedDevice();
 
@@ -529,7 +533,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void binderCallbacksWork() throws Exception {
         assumeSupportedDevice();
 
@@ -581,7 +585,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void vmConfigGetAndSetTests() {
         // Minimal has as little as specified as possible; everything that can be is defaulted.
         VirtualMachineConfig.Builder minimalBuilder =
@@ -650,7 +654,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void vmConfigBuilderValidationTests() {
         VirtualMachineConfig.Builder builder =
                 new VirtualMachineConfig.Builder(getContext()).setProtectedVm(mProtectedVm);
@@ -700,7 +704,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void compatibleConfigTests() {
         VirtualMachineConfig baseline = newBaselineBuilder().build();
 
@@ -787,7 +791,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void vmUnitTests() throws Exception {
         VirtualMachineConfig.Builder builder = newVmConfigBuilderWithPayloadBinary("binary.so");
         VirtualMachineConfig config = builder.build();
@@ -808,7 +812,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void testAvfRequiresUpdatableApex() throws Exception {
         assertWithMessage("Devices that support AVF must also support updatable APEX")
                 .that(SystemProperties.getBoolean("ro.apex.updatable", false))
@@ -816,7 +820,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void vmmGetAndCreate() throws Exception {
         assumeSupportedDevice();
 
@@ -863,7 +867,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void vmFilesStoredInDeDirWhenCreatedFromDEContext() throws Exception {
         final Context ctx = getContext().createDeviceProtectedStorageContext();
         final int userId = ctx.getUserId();
@@ -881,7 +885,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void vmFilesStoredInCeDirWhenCreatedFromCEContext() throws Exception {
         final Context ctx = getContext().createCredentialProtectedStorageContext();
         final int userId = ctx.getUserId();
@@ -898,7 +902,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void differentManagersForDifferentContexts() throws Exception {
         final Context ceCtx = getContext().createCredentialProtectedStorageContext();
         final Context deCtx = getContext().createDeviceProtectedStorageContext();
@@ -907,12 +911,7 @@
     }
 
     @Test
-    @CddTest(
-            requirements = {
-                "9.17/C-1-1",
-                "9.17/C-1-2",
-                "9.17/C-1-4",
-            })
+    @CddTest
     public void createVmWithConfigRequiresPermission() throws Exception {
         assumeSupportedDevice();
         revokePermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
@@ -934,10 +933,7 @@
     }
 
     @Test
-    @CddTest(
-            requirements = {
-                "9.17/C-1-1",
-            })
+    @CddTest
     public void deleteVm() throws Exception {
         assumeSupportedDevice();
 
@@ -961,10 +957,7 @@
     }
 
     @Test
-    @CddTest(
-            requirements = {
-                "9.17/C-1-1",
-            })
+    @CddTest
     public void deleteVmFiles() throws Exception {
         assumeSupportedDevice();
 
@@ -994,10 +987,7 @@
     }
 
     @Test
-    @CddTest(
-            requirements = {
-                "9.17/C-1-1",
-            })
+    @CddTest
     public void validApkPathIsAccepted() throws Exception {
         assumeSupportedDevice();
 
@@ -1022,7 +1012,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void invalidVmNameIsRejected() {
         VirtualMachineManager vmm = getVirtualMachineManager();
         assertThrows(IllegalArgumentException.class, () -> vmm.get("../foo"));
@@ -1030,7 +1020,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+    @CddTest
     public void extraApk() throws Exception {
         assumeSupportedDevice();
 
@@ -1055,7 +1045,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+    @CddTest
     public void extraApkInVmConfig() throws Exception {
         assumeSupportedDevice();
         assumeFeatureEnabled(VirtualMachineManager.FEATURE_MULTI_TENANT);
@@ -1114,7 +1104,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-7"})
+    @CddTest
     public void changingNonDebuggableVmDebuggableInvalidatesVmIdentity() throws Exception {
         // Debuggability changes initrd which is verified by pvmfw.
         // Therefore, skip this on non-protected VM.
@@ -1168,7 +1158,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-7"})
+    @CddTest
     public void changingDebuggableVmNonDebuggableInvalidatesVmIdentity() throws Exception {
         // Debuggability changes initrd which is verified by pvmfw.
         // Therefore, skip this on non-protected VM.
@@ -1249,7 +1239,8 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-7", "9.17/C-3-4"})
+    @CddTest
+    @GmsTest(requirements = {"GMS-3-7.1-011"})
     public void instancesOfSameVmHaveDifferentCdis() throws Exception {
         assumeSupportedDevice();
         // TODO(b/325094712): VMs on CF with same payload have the same secret. This is because
@@ -1276,7 +1267,8 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-7", "9.17/C-3-4"})
+    @CddTest
+    @GmsTest(requirements = {"GMS-3-7.1-011"})
     public void sameInstanceKeepsSameCdis() throws Exception {
         assumeSupportedDevice();
         assume().withMessage("Skip on CF. Too Slow. b/257270529").that(isCuttlefish()).isFalse();
@@ -1297,8 +1289,9 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-7"})
+    @CddTest
     @VsrTest(requirements = {"VSR-7.1-001.005"})
+    @GmsTest(requirements = {"GMS-VSR-7.1-001.004"})
     public void bccIsSuperficiallyWellFormed() throws Exception {
         assumeSupportedDevice();
 
@@ -1344,6 +1337,7 @@
 
     @Test
     @VsrTest(requirements = {"VSR-7.1-001.005"})
+    @GmsTest(requirements = {"GMS-VSR-7.1-001.004"})
     public void protectedVmHasValidDiceChain() throws Exception {
         // This test validates two things regarding the pVM DICE chain:
         // 1. The DICE chain is well-formed that all the entries conform to the DICE spec.
@@ -1377,7 +1371,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-1-2"})
+    @CddTest
     public void accessToCdisIsRestricted() throws Exception {
         assumeSupportedDevice();
 
@@ -1454,7 +1448,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-7"})
+    @GmsTest(requirements = {"GMS-3-7.1-006"})
     public void bootFailsWhenMicrodroidDataIsCompromised() throws Exception {
         // If Updatable VM is supported => No instance.img required
         assumeNoUpdatableVmSupport();
@@ -1462,7 +1456,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-7"})
+    @GmsTest(requirements = {"GMS-3-7.1-006"})
     public void bootFailsWhenPvmFwDataIsCompromised() throws Exception {
         // If Updatable VM is supported => No instance.img required
         assumeNoUpdatableVmSupport();
@@ -1475,6 +1469,7 @@
     }
 
     @Test
+    @GmsTest(requirements = {"GMS-3-7.1-006"})
     public void bootFailsWhenConfigIsInvalid() throws Exception {
         grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
         VirtualMachineConfig config =
@@ -1489,6 +1484,7 @@
     }
 
     @Test
+    @GmsTest(requirements = {"GMS-3-7.1-006"})
     public void bootFailsWhenBinaryNameIsInvalid() throws Exception {
         VirtualMachineConfig config =
                 newVmConfigBuilderWithPayloadBinary("DoesNotExist.so")
@@ -1502,6 +1498,7 @@
     }
 
     @Test
+    @GmsTest(requirements = {"GMS-3-7.1-006"})
     public void bootFailsWhenApkPathIsInvalid() {
         VirtualMachineConfig config =
                 newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
@@ -1515,6 +1512,7 @@
     }
 
     @Test
+    @GmsTest(requirements = {"GMS-3-7.1-006"})
     public void bootFailsWhenExtraApkPackageIsInvalid() {
         VirtualMachineConfig config =
                 newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
@@ -1558,6 +1556,7 @@
     }
 
     @Test
+    @GmsTest(requirements = {"GMS-3-7.1-006"})
     public void bootFailsWhenBinaryIsMissingEntryFunction() throws Exception {
         VirtualMachineConfig normalConfig =
                 newVmConfigBuilderWithPayloadBinary("MicrodroidEmptyNativeLib.so")
@@ -1570,6 +1569,7 @@
     }
 
     @Test
+    @GmsTest(requirements = {"GMS-3-7.1-006"})
     public void bootFailsWhenBinaryTriesToLinkAgainstPrivateLibs() throws Exception {
         VirtualMachineConfig normalConfig =
                 newVmConfigBuilderWithPayloadBinary("MicrodroidPrivateLinkingNativeLib.so")
@@ -1582,6 +1582,7 @@
     }
 
     @Test
+    @CddTest
     public void sameInstancesShareTheSameVmObject() throws Exception {
         VirtualMachineConfig config =
                 newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so").build();
@@ -1598,6 +1599,7 @@
     }
 
     @Test
+    @CddTest
     public void importedVmAndOriginalVmHaveTheSameCdi() throws Exception {
         assumeSupportedDevice();
         // Arrange
@@ -1693,7 +1695,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void encryptedStorageAvailable() throws Exception {
         assumeSupportedDevice();
 
@@ -1716,7 +1718,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void encryptedStorageIsInaccessibleToDifferentVm() throws Exception {
         assumeSupportedDevice();
         // TODO(b/325094712): VMs on CF with same payload have the same secret. This is because
@@ -1781,7 +1783,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+    @CddTest
     public void microdroidLauncherHasEmptyCapabilities() throws Exception {
         assumeSupportedDevice();
 
@@ -1805,7 +1807,8 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
+    @GmsTest(requirements = {"GMS-3-7.1-005"})
     public void payloadIsNotRoot() throws Exception {
         assumeSupportedDevice();
         assumeFeatureEnabled(VirtualMachineManager.FEATURE_MULTI_TENANT);
@@ -1828,7 +1831,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1"})
+    @CddTest
     public void encryptedStorageIsPersistent() throws Exception {
         assumeSupportedDevice();
 
@@ -1864,7 +1867,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+    @CddTest
     public void canReadFileFromAssets_debugFull() throws Exception {
         assumeSupportedDevice();
 
@@ -1888,6 +1891,7 @@
     }
 
     @Test
+    @CddTest
     public void outputShouldBeExplicitlyCaptured() throws Exception {
         assumeSupportedDevice();
 
@@ -1910,6 +1914,7 @@
     }
 
     @Test
+    @CddTest
     public void inputShouldBeExplicitlyAllowed() throws Exception {
         assumeSupportedDevice();
 
@@ -1961,6 +1966,7 @@
     }
 
     @Test
+    @CddTest
     public void outputIsRedirectedToLogcatIfNotCaptured() throws Exception {
         assumeSupportedDevice();
 
@@ -1981,6 +1987,7 @@
     }
 
     @Test
+    @CddTest
     public void outputIsNotRedirectedToLogcatIfNotDebuggable() throws Exception {
         assumeSupportedDevice();
 
@@ -1991,6 +1998,7 @@
     }
 
     @Test
+    @CddTest
     public void testConsoleInputSupported() throws Exception {
         assumeSupportedDevice();
         assumeFalse("Not supported on GKI kernels", mOs.startsWith("microdroid_gki-"));
@@ -2020,6 +2028,7 @@
     }
 
     @Test
+    @CddTest
     public void testStartVmWithPayloadOfAnotherApp() throws Exception {
         assumeSupportedDevice();
 
@@ -2049,6 +2058,7 @@
     }
 
     @Test
+    @CddTest
     public void testVmDescriptorParcelUnparcel_noTrustedStorage() throws Exception {
         assumeSupportedDevice();
 
@@ -2082,6 +2092,7 @@
     }
 
     @Test
+    @CddTest
     public void testVmDescriptorParcelUnparcel_withTrustedStorage() throws Exception {
         assumeSupportedDevice();
 
@@ -2135,6 +2146,7 @@
     }
 
     @Test
+    @CddTest
     public void testShareVmWithAnotherApp() throws Exception {
         assumeSupportedDevice();
 
@@ -2180,6 +2192,7 @@
     }
 
     @Test
+    @CddTest
     public void testShareVmWithAnotherApp_encryptedStorage() throws Exception {
         assumeSupportedDevice();
 
@@ -2249,7 +2262,8 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-5"})
+    @CddTest
+    @GmsTest(requirements = {"GMS-3-7.1-005"})
     public void testFileUnderBinHasExecutePermission() throws Exception {
         assumeSupportedDevice();
 
@@ -2292,7 +2306,7 @@
     private static final int MS_NOATIME = 1024;
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-5"})
+    @GmsTest(requirements = {"GMS-3-7.1-004", "GMS-3-7.1-005"})
     public void dataIsMountedWithNoExec() throws Exception {
         assumeSupportedDevice();
 
@@ -2317,7 +2331,7 @@
     }
 
     @Test
-    @CddTest(requirements = {"9.17/C-1-5"})
+    @GmsTest(requirements = {"GMS-3-7.1-004", "GMS-3-7.1-005"})
     public void encryptedStoreIsMountedWithNoExec() throws Exception {
         assumeSupportedDevice();
 
@@ -2343,7 +2357,6 @@
     }
 
     @Test
-    @VsrTest(requirements = {"VSR-7.1-001.003"})
     public void kernelVersionRequirement() throws Exception {
         assumeVsrCompliant();
         int firstApiLevel = SystemProperties.getInt("ro.product.first_api_level", 0);
@@ -2445,6 +2458,9 @@
     }
 
     @Test
+    @CddTest
+    @GmsTest(requirements = {"GMS-VSR-7.1-001.007"})
+    @VsrTest(requirements = {"VSR-7.1-001.008"})
     public void configuringVendorDiskImageRequiresCustomPermission() throws Exception {
         File vendorDiskImage =
                 new File("/data/local/tmp/cts/microdroid/test_microdroid_vendor_image.img");
@@ -2462,6 +2478,9 @@
     }
 
     @Test
+    @CddTest
+    @GmsTest(requirements = {"GMS-VSR-7.1-001.007"})
+    @VsrTest(requirements = {"VSR-7.1-001.008"})
     public void bootsWithVendorPartition() throws Exception {
         File vendorDiskImage = new File("/vendor/etc/avf/microdroid/microdroid_vendor.img");
         assumeTrue("Microdroid vendor image doesn't exist, skip", vendorDiskImage.exists());
@@ -2481,6 +2500,9 @@
     }
 
     @Test
+    @CddTest
+    @GmsTest(requirements = {"GMS-VSR-7.1-001.007"})
+    @VsrTest(requirements = {"VSR-7.1-001.008"})
     public void bootsWithCustomVendorPartitionForNonPvm() throws Exception {
         assumeNonProtectedVM();
         File vendorDiskImage =
@@ -2502,6 +2524,9 @@
     }
 
     @Test
+    @CddTest
+    @GmsTest(requirements = {"GMS-VSR-7.1-001.007"})
+    @VsrTest(requirements = {"VSR-7.1-001.008"})
     public void bootFailsWithCustomVendorPartitionForPvm() throws Exception {
         assumeProtectedVM();
         File vendorDiskImage =
@@ -2514,6 +2539,9 @@
     }
 
     @Test
+    @CddTest
+    @GmsTest(requirements = {"GMS-VSR-7.1-001.007"})
+    @VsrTest(requirements = {"VSR-7.1-001.008"})
     public void creationFailsWithUnsignedVendorPartition() throws Exception {
         File vendorDiskImage =
                 new File(
@@ -2526,6 +2554,7 @@
     }
 
     @Test
+    @GmsTest(requirements = {"GMS-3-7.1-004", "GMS-3-7.1-005"})
     public void systemPartitionMountFlags() throws Exception {
         assumeSupportedDevice();