Merge "Import translations. DO NOT MERGE ANYWHERE" into main
diff --git a/build/avf_flags.aconfig b/build/avf_flags.aconfig
index 9815c60..921c374 100644
--- a/build/avf_flags.aconfig
+++ b/build/avf_flags.aconfig
@@ -9,3 +9,11 @@
   bug: "383347947"
   is_fixed_read_only: true
 }
+
+flag {
+  name: "terminal_gui_support"
+  is_exported: true
+  namespace: "virtualization"
+  description: "Flag for GUI support in terminal"
+  bug: "386296118"
+}
\ No newline at end of file
diff --git a/libs/dice/open_dice/Android.bp b/libs/dice/open_dice/Android.bp
index f799fb1..1870ab6 100644
--- a/libs/dice/open_dice/Android.bp
+++ b/libs/dice/open_dice/Android.bp
@@ -128,7 +128,7 @@
 
 rust_defaults {
     name: "libopen_dice_cbor_bindgen.rust_defaults",
-    wrapper_src: "bindgen/dice.h",
+    wrapper_src: "bindgen/dice/dice.h",
     crate_name: "open_dice_cbor_bindgen",
     source_stem: "bindings",
     bindgen_flags: [
@@ -184,7 +184,7 @@
 
 rust_defaults {
     name: "libopen_dice_android_bindgen.rust_defaults",
-    wrapper_src: "bindgen/android.h",
+    wrapper_src: "bindgen/android/android.h",
     crate_name: "open_dice_android_bindgen",
     source_stem: "bindings",
     bindgen_flags: [
@@ -264,3 +264,9 @@
     clippy_lints: "none",
     lints: "none",
 }
+
+dirgroup {
+    name: "trusty_dirgroup_packages_modules_virtualization_libs_open_dice",
+    visibility: ["//trusty/vendor/google/aosp/scripts"],
+    dirs: ["."],
+}
diff --git a/libs/dice/open_dice/bindgen/android.h b/libs/dice/open_dice/bindgen/android/android.h
similarity index 100%
rename from libs/dice/open_dice/bindgen/android.h
rename to libs/dice/open_dice/bindgen/android/android.h
diff --git a/libs/dice/open_dice/bindgen/android/lib.rs b/libs/dice/open_dice/bindgen/android/lib.rs
new file mode 100644
index 0000000..7c300de
--- /dev/null
+++ b/libs/dice/open_dice/bindgen/android/lib.rs
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+// Get the bindgen definitions.
+// The trusty build system doesn't have support for packaging generated
+// bindgen sources as a crate automatically. In the Android tree, this
+// entire file is not used.
+
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(unused)]
+
+include!(env!("BINDGEN_INC_FILE"));
diff --git a/libs/dice/open_dice/bindgen/android/rules.mk b/libs/dice/open_dice/bindgen/android/rules.mk
new file mode 100644
index 0000000..200ec52
--- /dev/null
+++ b/libs/dice/open_dice/bindgen/android/rules.mk
@@ -0,0 +1,54 @@
+# Copyright (C) 2024 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)/lib.rs
+
+MODULE_CRATE_NAME := open_dice_android_bindgen
+
+MODULE_LIBRARY_DEPS += \
+	external/open-dice \
+	$(LOCAL_DIR)/../dice \
+	trusty/user/base/lib/trusty-sys \
+
+MODULE_BINDGEN_ALLOW_FUNCTIONS := \
+	DiceAndroidFormatConfigDescriptor \
+	DiceAndroidMainFlow \
+	DiceAndroidHandoverParse \
+
+MODULE_BINDGEN_ALLOW_VARS := \
+	DICE_ANDROID_CONFIG_.* \
+
+# Prevent DiceInputValues from being generated a second time and
+# import it instead from open_dice_cbor_bindgen.
+MODULE_BINDGEN_FLAGS += \
+	--blocklist-type="DiceInputValues_" \
+	--blocklist-type="DiceInputValues" \
+	--raw-line \
+	"pub use open_dice_cbor_bindgen::DiceInputValues;" \
+
+# Prevent DiceResult from being generated a second time and
+# import it instead from open_dice_cbor_bindgen.
+MODULE_BINDGEN_FLAGS += \
+	--blocklist-type="DiceResult" \
+	--raw-line \
+	"pub use open_dice_cbor_bindgen::DiceResult;" \
+
+MODULE_BINDGEN_SRC_HEADER := $(LOCAL_DIR)/android.h
+
+include make/library.mk
diff --git a/libs/dice/open_dice/bindgen/dice.h b/libs/dice/open_dice/bindgen/dice/dice.h
similarity index 100%
rename from libs/dice/open_dice/bindgen/dice.h
rename to libs/dice/open_dice/bindgen/dice/dice.h
diff --git a/libs/dice/open_dice/bindgen/dice/lib.rs b/libs/dice/open_dice/bindgen/dice/lib.rs
new file mode 100644
index 0000000..ed2fd23
--- /dev/null
+++ b/libs/dice/open_dice/bindgen/dice/lib.rs
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Get the bindgen definitions.
+// The trusty build system doesn't have support for packaging generated
+// bindgen sources as a crate automatically. In the Android tree, this
+// entire file is not used.
+
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(unused)]
+
+include!(env!("BINDGEN_INC_FILE"));
diff --git a/libs/dice/open_dice/bindgen/dice/rules.mk b/libs/dice/open_dice/bindgen/dice/rules.mk
new file mode 100644
index 0000000..0ea5c7c
--- /dev/null
+++ b/libs/dice/open_dice/bindgen/dice/rules.mk
@@ -0,0 +1,56 @@
+# Copyright (C) 2024 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)/lib.rs
+
+MODULE_CRATE_NAME := open_dice_cbor_bindgen
+
+MODULE_LIBRARY_DEPS += \
+	external/open-dice \
+	trusty/user/base/lib/trusty-sys \
+
+MODULE_BINDGEN_FLAGS += \
+	--rustified-enum DiceConfigType \
+	--rustified-enum DiceMode \
+	--rustified-enum DiceResult \
+	--rustified-enum DicePrincipal \
+
+MODULE_BINDGEN_ALLOW_FUNCTIONS := \
+	DiceDeriveCdiPrivateKeySeed \
+	DiceDeriveCdiCertificateId \
+	DiceMainFlow \
+	DiceHash \
+	DiceKdf \
+	DiceKeypairFromSeed \
+	DiceSign \
+	DiceVerify \
+	DiceGenerateCertificate \
+
+MODULE_BINDGEN_ALLOW_VARS := \
+	DICE_CDI_SIZE \
+	DICE_HASH_SIZE \
+	DICE_HIDDEN_SIZE \
+	DICE_INLINE_CONFIG_SIZE \
+	DICE_PRIVATE_KEY_SEED_SIZE \
+	DICE_ID_SIZE \
+	DICE_PRIVATE_KEY_BUFFER_SIZE \
+
+MODULE_BINDGEN_SRC_HEADER := $(LOCAL_DIR)/dice.h
+
+include make/library.mk
diff --git a/libs/dice/open_dice/rules.mk b/libs/dice/open_dice/rules.mk
new file mode 100644
index 0000000..d84468d
--- /dev/null
+++ b/libs/dice/open_dice/rules.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2024 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_open_dice
+
+MODULE_LIBRARY_DEPS += \
+	$(call FIND_CRATE,coset) \
+	$(call FIND_CRATE,zeroize) \
+	$(LOCAL_DIR)/bindgen/android \
+	$(LOCAL_DIR)/bindgen/dice \
+
+include make/library.mk
diff --git a/libs/dice/open_dice/src/bcc.rs b/libs/dice/open_dice/src/bcc.rs
index fabd7c7..a3ddd76 100644
--- a/libs/dice/open_dice/src/bcc.rs
+++ b/libs/dice/open_dice/src/bcc.rs
@@ -41,7 +41,7 @@
 }
 
 /// Formats a configuration descriptor following the Android Profile for DICE specification.
-/// See https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/android.md.
+/// See <https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/android.md>.
 pub fn bcc_format_config_descriptor(values: &DiceConfigValues, buffer: &mut [u8]) -> Result<usize> {
     let mut configs = 0;
 
diff --git a/libs/dice/open_dice/tests/api_test.rs b/libs/dice/open_dice/tests/api_test.rs
index a47265b..d3a91ff 100644
--- a/libs/dice/open_dice/tests/api_test.rs
+++ b/libs/dice/open_dice/tests/api_test.rs
@@ -14,94 +14,108 @@
  * limitations under the License.
  */
 
-use diced_open_dice::{
-    derive_cdi_certificate_id, derive_cdi_private_key_seed, hash, kdf, keypair_from_seed, sign,
-    verify, CDI_SIZE, HASH_SIZE, ID_SIZE, PRIVATE_KEY_SEED_SIZE,
-};
+#[cfg(test)]
+mod tests {
+    use diced_open_dice::{
+        derive_cdi_certificate_id, derive_cdi_private_key_seed, hash, kdf, keypair_from_seed, sign,
+        verify, CDI_SIZE, HASH_SIZE, ID_SIZE, PRIVATE_KEY_SEED_SIZE,
+    };
 
-#[test]
-fn hash_succeeds() {
-    const EXPECTED_HASH: [u8; HASH_SIZE] = [
-        0x30, 0x9e, 0xcc, 0x48, 0x9c, 0x12, 0xd6, 0xeb, 0x4c, 0xc4, 0x0f, 0x50, 0xc9, 0x02, 0xf2,
-        0xb4, 0xd0, 0xed, 0x77, 0xee, 0x51, 0x1a, 0x7c, 0x7a, 0x9b, 0xcd, 0x3c, 0xa8, 0x6d, 0x4c,
-        0xd8, 0x6f, 0x98, 0x9d, 0xd3, 0x5b, 0xc5, 0xff, 0x49, 0x96, 0x70, 0xda, 0x34, 0x25, 0x5b,
-        0x45, 0xb0, 0xcf, 0xd8, 0x30, 0xe8, 0x1f, 0x60, 0x5d, 0xcf, 0x7d, 0xc5, 0x54, 0x2e, 0x93,
-        0xae, 0x9c, 0xd7, 0x6f,
+    // This test initialization is only required for the trusty test harness.
+    #[cfg(feature = "trusty")]
+    test::init!();
+
+    #[test]
+    fn hash_succeeds() {
+        const EXPECTED_HASH: [u8; HASH_SIZE] = [
+            0x30, 0x9e, 0xcc, 0x48, 0x9c, 0x12, 0xd6, 0xeb, 0x4c, 0xc4, 0x0f, 0x50, 0xc9, 0x02,
+            0xf2, 0xb4, 0xd0, 0xed, 0x77, 0xee, 0x51, 0x1a, 0x7c, 0x7a, 0x9b, 0xcd, 0x3c, 0xa8,
+            0x6d, 0x4c, 0xd8, 0x6f, 0x98, 0x9d, 0xd3, 0x5b, 0xc5, 0xff, 0x49, 0x96, 0x70, 0xda,
+            0x34, 0x25, 0x5b, 0x45, 0xb0, 0xcf, 0xd8, 0x30, 0xe8, 0x1f, 0x60, 0x5d, 0xcf, 0x7d,
+            0xc5, 0x54, 0x2e, 0x93, 0xae, 0x9c, 0xd7, 0x6f,
+        ];
+        assert_eq!(EXPECTED_HASH, hash(b"hello world").expect("hash failed"));
+    }
+
+    #[test]
+    fn kdf_succeeds() {
+        let mut derived_key = [0u8; PRIVATE_KEY_SEED_SIZE];
+        kdf(b"myInitialKeyMaterial", b"mySalt", b"myInfo", &mut derived_key).unwrap();
+        const EXPECTED_DERIVED_KEY: [u8; PRIVATE_KEY_SEED_SIZE] = [
+            0x91, 0x9b, 0x8d, 0x29, 0xc4, 0x1b, 0x93, 0xd7, 0xeb, 0x09, 0xfa, 0xd7, 0xc9, 0x87,
+            0xb0, 0xd1, 0xcc, 0x26, 0xef, 0x07, 0x83, 0x42, 0xcf, 0xa3, 0x45, 0x0a, 0x57, 0xe9,
+            0x19, 0x86, 0xef, 0x48,
+        ];
+        assert_eq!(EXPECTED_DERIVED_KEY, derived_key);
+    }
+
+    #[test]
+    fn derive_cdi_certificate_id_succeeds() {
+        const EXPECTED_ID: [u8; ID_SIZE] = [
+            0x7a, 0x36, 0x45, 0x2c, 0x02, 0xf6, 0x2b, 0xec, 0xf9, 0x80, 0x06, 0x75, 0x87, 0xa5,
+            0xc1, 0x44, 0x0c, 0xd3, 0xc0, 0x6d,
+        ];
+        assert_eq!(EXPECTED_ID, derive_cdi_certificate_id(b"MyPubKey").unwrap());
+    }
+
+    const EXPECTED_SEED: &[u8] = &[
+        0xfa, 0x3c, 0x2f, 0x58, 0x37, 0xf5, 0x8e, 0x96, 0x16, 0x09, 0xf5, 0x22, 0xa1, 0xf1, 0xba,
+        0xaa, 0x19, 0x95, 0x01, 0x79, 0x2e, 0x60, 0x56, 0xaf, 0xf6, 0x41, 0xe7, 0xff, 0x48, 0xf5,
+        0x3a, 0x08, 0x84, 0x8a, 0x98, 0x85, 0x6d, 0xf5, 0x69, 0x21, 0x03, 0xcd, 0x09, 0xc3, 0x28,
+        0xd6, 0x06, 0xa7, 0x57, 0xbd, 0x48, 0x4b, 0x0f, 0x79, 0x0f, 0xf8, 0x2f, 0xf0, 0x0a, 0x41,
+        0x94, 0xd8, 0x8c, 0xa8,
     ];
-    assert_eq!(EXPECTED_HASH, hash(b"hello world").expect("hash failed"));
-}
 
-#[test]
-fn kdf_succeeds() {
-    let mut derived_key = [0u8; PRIVATE_KEY_SEED_SIZE];
-    kdf(b"myInitialKeyMaterial", b"mySalt", b"myInfo", &mut derived_key).unwrap();
-    const EXPECTED_DERIVED_KEY: [u8; PRIVATE_KEY_SEED_SIZE] = [
-        0x91, 0x9b, 0x8d, 0x29, 0xc4, 0x1b, 0x93, 0xd7, 0xeb, 0x09, 0xfa, 0xd7, 0xc9, 0x87, 0xb0,
-        0xd1, 0xcc, 0x26, 0xef, 0x07, 0x83, 0x42, 0xcf, 0xa3, 0x45, 0x0a, 0x57, 0xe9, 0x19, 0x86,
-        0xef, 0x48,
+    const EXPECTED_CDI_ATTEST: &[u8] = &[
+        0xfa, 0x3c, 0x2f, 0x58, 0x37, 0xf5, 0x8e, 0x96, 0x16, 0x09, 0xf5, 0x22, 0xa1, 0xf1, 0xba,
+        0xaa, 0x19, 0x95, 0x01, 0x79, 0x2e, 0x60, 0x56, 0xaf, 0xf6, 0x41, 0xe7, 0xff, 0x48, 0xf5,
+        0x3a, 0x08,
     ];
-    assert_eq!(EXPECTED_DERIVED_KEY, derived_key);
-}
 
-#[test]
-fn derive_cdi_certificate_id_succeeds() {
-    const EXPECTED_ID: [u8; ID_SIZE] = [
-        0x7a, 0x36, 0x45, 0x2c, 0x02, 0xf6, 0x2b, 0xec, 0xf9, 0x80, 0x06, 0x75, 0x87, 0xa5, 0xc1,
-        0x44, 0x0c, 0xd3, 0xc0, 0x6d,
+    const EXPECTED_CDI_PRIVATE_KEY_SEED: &[u8] = &[
+        0x5f, 0xcc, 0x8e, 0x1a, 0xd1, 0xc2, 0xb3, 0xe9, 0xfb, 0xe1, 0x68, 0xf0, 0xf6, 0x98, 0xfe,
+        0x0d, 0xee, 0xd4, 0xb5, 0x18, 0xcb, 0x59, 0x70, 0x2d, 0xee, 0x06, 0xe5, 0x70, 0xf1, 0x72,
+        0x02, 0x6e,
     ];
-    assert_eq!(EXPECTED_ID, derive_cdi_certificate_id(b"MyPubKey").unwrap());
-}
 
-const EXPECTED_SEED: &[u8] = &[
-    0xfa, 0x3c, 0x2f, 0x58, 0x37, 0xf5, 0x8e, 0x96, 0x16, 0x09, 0xf5, 0x22, 0xa1, 0xf1, 0xba, 0xaa,
-    0x19, 0x95, 0x01, 0x79, 0x2e, 0x60, 0x56, 0xaf, 0xf6, 0x41, 0xe7, 0xff, 0x48, 0xf5, 0x3a, 0x08,
-    0x84, 0x8a, 0x98, 0x85, 0x6d, 0xf5, 0x69, 0x21, 0x03, 0xcd, 0x09, 0xc3, 0x28, 0xd6, 0x06, 0xa7,
-    0x57, 0xbd, 0x48, 0x4b, 0x0f, 0x79, 0x0f, 0xf8, 0x2f, 0xf0, 0x0a, 0x41, 0x94, 0xd8, 0x8c, 0xa8,
-];
+    const EXPECTED_PUB_KEY: &[u8] = &[
+        0x47, 0x42, 0x4b, 0xbd, 0xd7, 0x23, 0xb4, 0xcd, 0xca, 0xe2, 0x8e, 0xdc, 0x6b, 0xfc, 0x23,
+        0xc9, 0x21, 0x5c, 0x48, 0x21, 0x47, 0xee, 0x5b, 0xfa, 0xaf, 0x88, 0x9a, 0x52, 0xf1, 0x61,
+        0x06, 0x37,
+    ];
+    const EXPECTED_PRIV_KEY: &[u8] = &[
+        0x5f, 0xcc, 0x8e, 0x1a, 0xd1, 0xc2, 0xb3, 0xe9, 0xfb, 0xe1, 0x68, 0xf0, 0xf6, 0x98, 0xfe,
+        0x0d, 0xee, 0xd4, 0xb5, 0x18, 0xcb, 0x59, 0x70, 0x2d, 0xee, 0x06, 0xe5, 0x70, 0xf1, 0x72,
+        0x02, 0x6e, 0x47, 0x42, 0x4b, 0xbd, 0xd7, 0x23, 0xb4, 0xcd, 0xca, 0xe2, 0x8e, 0xdc, 0x6b,
+        0xfc, 0x23, 0xc9, 0x21, 0x5c, 0x48, 0x21, 0x47, 0xee, 0x5b, 0xfa, 0xaf, 0x88, 0x9a, 0x52,
+        0xf1, 0x61, 0x06, 0x37,
+    ];
 
-const EXPECTED_CDI_ATTEST: &[u8] = &[
-    0xfa, 0x3c, 0x2f, 0x58, 0x37, 0xf5, 0x8e, 0x96, 0x16, 0x09, 0xf5, 0x22, 0xa1, 0xf1, 0xba, 0xaa,
-    0x19, 0x95, 0x01, 0x79, 0x2e, 0x60, 0x56, 0xaf, 0xf6, 0x41, 0xe7, 0xff, 0x48, 0xf5, 0x3a, 0x08,
-];
+    const EXPECTED_SIGNATURE: &[u8] = &[
+        0x44, 0xae, 0xcc, 0xe2, 0xb9, 0x96, 0x18, 0x39, 0x0e, 0x61, 0x0f, 0x53, 0x07, 0xbf, 0xf2,
+        0x32, 0x3d, 0x44, 0xd4, 0xf2, 0x07, 0x23, 0x30, 0x85, 0x32, 0x18, 0xd2, 0x69, 0xb8, 0x29,
+        0x3c, 0x26, 0xe6, 0x0d, 0x9c, 0xa5, 0xc2, 0x73, 0xcd, 0x8c, 0xb8, 0x3c, 0x3e, 0x5b, 0xfd,
+        0x62, 0x8d, 0xf6, 0xc4, 0x27, 0xa6, 0xe9, 0x11, 0x06, 0x5a, 0xb2, 0x2b, 0x64, 0xf7, 0xfc,
+        0xbb, 0xab, 0x4a, 0x0e,
+    ];
 
-const EXPECTED_CDI_PRIVATE_KEY_SEED: &[u8] = &[
-    0x5f, 0xcc, 0x8e, 0x1a, 0xd1, 0xc2, 0xb3, 0xe9, 0xfb, 0xe1, 0x68, 0xf0, 0xf6, 0x98, 0xfe, 0x0d,
-    0xee, 0xd4, 0xb5, 0x18, 0xcb, 0x59, 0x70, 0x2d, 0xee, 0x06, 0xe5, 0x70, 0xf1, 0x72, 0x02, 0x6e,
-];
-
-const EXPECTED_PUB_KEY: &[u8] = &[
-    0x47, 0x42, 0x4b, 0xbd, 0xd7, 0x23, 0xb4, 0xcd, 0xca, 0xe2, 0x8e, 0xdc, 0x6b, 0xfc, 0x23, 0xc9,
-    0x21, 0x5c, 0x48, 0x21, 0x47, 0xee, 0x5b, 0xfa, 0xaf, 0x88, 0x9a, 0x52, 0xf1, 0x61, 0x06, 0x37,
-];
-const EXPECTED_PRIV_KEY: &[u8] = &[
-    0x5f, 0xcc, 0x8e, 0x1a, 0xd1, 0xc2, 0xb3, 0xe9, 0xfb, 0xe1, 0x68, 0xf0, 0xf6, 0x98, 0xfe, 0x0d,
-    0xee, 0xd4, 0xb5, 0x18, 0xcb, 0x59, 0x70, 0x2d, 0xee, 0x06, 0xe5, 0x70, 0xf1, 0x72, 0x02, 0x6e,
-    0x47, 0x42, 0x4b, 0xbd, 0xd7, 0x23, 0xb4, 0xcd, 0xca, 0xe2, 0x8e, 0xdc, 0x6b, 0xfc, 0x23, 0xc9,
-    0x21, 0x5c, 0x48, 0x21, 0x47, 0xee, 0x5b, 0xfa, 0xaf, 0x88, 0x9a, 0x52, 0xf1, 0x61, 0x06, 0x37,
-];
-
-const EXPECTED_SIGNATURE: &[u8] = &[
-    0x44, 0xae, 0xcc, 0xe2, 0xb9, 0x96, 0x18, 0x39, 0x0e, 0x61, 0x0f, 0x53, 0x07, 0xbf, 0xf2, 0x32,
-    0x3d, 0x44, 0xd4, 0xf2, 0x07, 0x23, 0x30, 0x85, 0x32, 0x18, 0xd2, 0x69, 0xb8, 0x29, 0x3c, 0x26,
-    0xe6, 0x0d, 0x9c, 0xa5, 0xc2, 0x73, 0xcd, 0x8c, 0xb8, 0x3c, 0x3e, 0x5b, 0xfd, 0x62, 0x8d, 0xf6,
-    0xc4, 0x27, 0xa6, 0xe9, 0x11, 0x06, 0x5a, 0xb2, 0x2b, 0x64, 0xf7, 0xfc, 0xbb, 0xab, 0x4a, 0x0e,
-];
-
-#[test]
-fn hash_derive_sign_verify() {
-    let seed = hash(b"MySeedString").unwrap();
-    assert_eq!(seed, EXPECTED_SEED);
-    let cdi_attest = &seed[..CDI_SIZE];
-    assert_eq!(cdi_attest, EXPECTED_CDI_ATTEST);
-    let cdi_private_key_seed = derive_cdi_private_key_seed(cdi_attest.try_into().unwrap()).unwrap();
-    assert_eq!(cdi_private_key_seed.as_array(), EXPECTED_CDI_PRIVATE_KEY_SEED);
-    let (pub_key, priv_key) = keypair_from_seed(cdi_private_key_seed.as_array()).unwrap();
-    assert_eq!(&pub_key, EXPECTED_PUB_KEY);
-    assert_eq!(priv_key.as_array(), EXPECTED_PRIV_KEY);
-    let mut signature = sign(b"MyMessage", priv_key.as_array()).unwrap();
-    assert_eq!(&signature, EXPECTED_SIGNATURE);
-    assert!(verify(b"MyMessage", &signature, &pub_key).is_ok());
-    assert!(verify(b"MyMessage_fail", &signature, &pub_key).is_err());
-    signature[0] += 1;
-    assert!(verify(b"MyMessage", &signature, &pub_key).is_err());
+    #[test]
+    fn hash_derive_sign_verify() {
+        let seed = hash(b"MySeedString").unwrap();
+        assert_eq!(seed, EXPECTED_SEED);
+        let cdi_attest = &seed[..CDI_SIZE];
+        assert_eq!(cdi_attest, EXPECTED_CDI_ATTEST);
+        let cdi_private_key_seed =
+            derive_cdi_private_key_seed(cdi_attest.try_into().unwrap()).unwrap();
+        assert_eq!(cdi_private_key_seed.as_array(), EXPECTED_CDI_PRIVATE_KEY_SEED);
+        let (pub_key, priv_key) = keypair_from_seed(cdi_private_key_seed.as_array()).unwrap();
+        assert_eq!(&pub_key, EXPECTED_PUB_KEY);
+        assert_eq!(priv_key.as_array(), EXPECTED_PRIV_KEY);
+        let mut signature = sign(b"MyMessage", priv_key.as_array()).unwrap();
+        assert_eq!(&signature, EXPECTED_SIGNATURE);
+        assert!(verify(b"MyMessage", &signature, &pub_key).is_ok());
+        assert!(verify(b"MyMessage_fail", &signature, &pub_key).is_err());
+        signature[0] += 1;
+        assert!(verify(b"MyMessage", &signature, &pub_key).is_err());
+    }
 }
diff --git a/libs/dice/open_dice/tests/manifest.json b/libs/dice/open_dice/tests/manifest.json
new file mode 100644
index 0000000..28db874
--- /dev/null
+++ b/libs/dice/open_dice/tests/manifest.json
@@ -0,0 +1,9 @@
+{
+    "app_name": "diced_open_dice_tests",
+    "uuid": "0b772481-7c24-4b9b-9d7c-441ac10d969b",
+    "min_heap": 32768,
+    "min_stack": 32768,
+    "mgmt_flags": {
+        "non_critical_app": true
+    }
+}
diff --git a/libs/dice/open_dice/tests/rules.mk b/libs/dice/open_dice/tests/rules.mk
new file mode 100644
index 0000000..a9d332c
--- /dev/null
+++ b/libs/dice/open_dice/tests/rules.mk
@@ -0,0 +1,35 @@
+# Copyright (C) 2024 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)/api_test.rs
+
+MODULE_CRATE_NAME := diced_open_dice_tests
+
+MODULE_LIBRARY_DEPS += \
+	packages/modules/Virtualization/libs/dice/open_dice \
+
+MODULE_RUST_TESTS := true
+
+# Enables trusty test initialization
+MODULE_RUSTFLAGS += \
+	--cfg 'feature="trusty"' \
+
+MANIFEST := $(LOCAL_DIR)/manifest.json
+
+include make/library.mk
diff --git a/libs/libavf/Android.bp b/libs/libavf/Android.bp
index b583e21..c958796 100644
--- a/libs/libavf/Android.bp
+++ b/libs/libavf/Android.bp
@@ -10,7 +10,10 @@
     source_stem: "bindings",
     bindgen_flags: ["--default-enum-style rust"],
     apex_available: ["com.android.virt"],
-    visibility: ["//packages/modules/Virtualization/tests/vts"],
+    visibility: [
+        "//packages/modules/Virtualization/tests/vts",
+        "//packages/modules/Virtualization/tests/old_images_avf_test",
+    ],
 }
 
 rust_defaults {
diff --git a/tests/old_images_avf_test/Android.bp b/tests/old_images_avf_test/Android.bp
new file mode 100644
index 0000000..b3d5baf
--- /dev/null
+++ b/tests/old_images_avf_test/Android.bp
@@ -0,0 +1,57 @@
+prebuilt_etc {
+    name: "backcompat_rialto_kernel",
+    filename: "rialto.bin",
+    src: ":empty_file",
+    target: {
+        android_arm64: {
+            src: ":rialto_signed",
+        },
+    },
+    installable: false,
+    visibility: ["//visibility:private"],
+}
+
+prebuilt_etc {
+    name: "android16_rialto_kernel",
+    filename: "android16_rialto.bin",
+    src: ":empty_file",
+    target: {
+        android_arm64: {
+            src: "images/android16_rialto.bin",
+        },
+    },
+    installable: false,
+    visibility: ["//visibility:private"],
+}
+
+rust_test {
+    name: "old_images_avf_test",
+    crate_name: "old_images_avf_test",
+    srcs: ["src/main.rs"],
+    rustlibs: [
+        "libanyhow",
+        "libavf_bindgen",
+        "libciborium",
+        "liblog_rust",
+        "libhypervisor_props",
+        "libscopeguard",
+        "libservice_vm_comm",
+        "libvsock",
+    ],
+    shared_libs: ["libavf"],
+    test_suites: [
+        "general-tests",
+    ],
+    data: [
+        ":android16_rialto_kernel",
+        ":backcompat_rialto_kernel",
+    ],
+    enabled: false,
+    target: {
+        android_arm64: {
+            enabled: true,
+        },
+    },
+    test_config: "AndroidTest.xml",
+    compile_multilib: "first",
+}
diff --git a/tests/old_images_avf_test/AndroidTest.xml b/tests/old_images_avf_test/AndroidTest.xml
new file mode 100644
index 0000000..089a424
--- /dev/null
+++ b/tests/old_images_avf_test/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs old images on current AVF VM.">
+    <option name="test-suite-tag" value="general-tests" />
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="old_images_avf_test->/data/local/tmp/old_images_avf_test" />
+        <option name="push" value="rialto.bin->/data/local/tmp/rialto.bin" />
+        <option name="push" value="android16_rialto.bin->/data/local/tmp/android16_rialto.bin" />
+    </target_preparer>
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.ArchModuleController">
+        <option name="arch" value="arm64" />
+    </object>
+    <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
+        <option name="test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="old_images_avf_test" />
+        <!-- rialto uses a fixed port number for the host, can't run two tests at the same time -->
+        <option name="native-test-flag" value="--test-threads=1" />
+    </test>
+</configuration>
diff --git a/tests/old_images_avf_test/images/android16_rialto.bin b/tests/old_images_avf_test/images/android16_rialto.bin
new file mode 100644
index 0000000..ff4c38e
--- /dev/null
+++ b/tests/old_images_avf_test/images/android16_rialto.bin
Binary files differ
diff --git a/tests/old_images_avf_test/src/main.rs b/tests/old_images_avf_test/src/main.rs
new file mode 100644
index 0000000..018a80e
--- /dev/null
+++ b/tests/old_images_avf_test/src/main.rs
@@ -0,0 +1,229 @@
+// 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 a VM with older images
+
+use anyhow::{bail, ensure, Context, Result};
+use log::info;
+use std::ffi::CStr;
+use std::fs::File;
+use std::io::{self, BufWriter, Write};
+use std::os::fd::IntoRawFd;
+use std::time::{Duration, Instant};
+use vsock::{VsockListener, VsockStream, VMADDR_CID_HOST};
+
+use avf_bindgen::*;
+use service_vm_comm::{Request, Response, ServiceVmRequest, VmType};
+
+const VM_MEMORY_MB: i32 = 16;
+const WRITE_BUFFER_CAPACITY: usize = 512;
+
+const LISTEN_TIMEOUT: Duration = Duration::from_secs(10);
+const READ_TIMEOUT: Duration = Duration::from_secs(10);
+const WRITE_TIMEOUT: Duration = Duration::from_secs(10);
+const STOP_TIMEOUT: timespec = timespec { tv_sec: 10, tv_nsec: 0 };
+
+/// Processes the request in the service VM.
+fn process_request(vsock_stream: &mut VsockStream, request: Request) -> Result<Response> {
+    write_request(vsock_stream, &ServiceVmRequest::Process(request))?;
+    read_response(vsock_stream)
+}
+
+/// Sends the request to the service VM.
+fn write_request(vsock_stream: &mut VsockStream, request: &ServiceVmRequest) -> Result<()> {
+    let mut buffer = BufWriter::with_capacity(WRITE_BUFFER_CAPACITY, vsock_stream);
+    ciborium::into_writer(request, &mut buffer)?;
+    buffer.flush().context("Failed to flush the buffer")?;
+    Ok(())
+}
+
+/// Reads the response from the service VM.
+fn read_response(vsock_stream: &mut VsockStream) -> Result<Response> {
+    let response: Response = ciborium::from_reader(vsock_stream)
+        .context("Failed to read the response from the service VM")?;
+    Ok(response)
+}
+
+fn listen_from_guest(port: u32) -> Result<VsockStream> {
+    let vsock_listener =
+        VsockListener::bind_with_cid_port(VMADDR_CID_HOST, port).context("Failed to bind vsock")?;
+    vsock_listener.set_nonblocking(true).context("Failed to set nonblocking")?;
+    let start_time = Instant::now();
+    loop {
+        if start_time.elapsed() >= LISTEN_TIMEOUT {
+            bail!("Timeout while listening");
+        }
+        match vsock_listener.accept() {
+            Ok((vsock_stream, _peer_addr)) => return Ok(vsock_stream),
+            Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
+                std::thread::sleep(Duration::from_millis(100));
+            }
+            Err(e) => bail!("Failed to listen: {e:?}"),
+        }
+    }
+}
+
+fn run_vm(image_path: &str, test_name: &CStr, protected_vm: bool) -> Result<()> {
+    let kernel_file = File::open(image_path).context("Failed to open kernel file")?;
+    let kernel_fd = kernel_file.into_raw_fd();
+
+    // SAFETY: AVirtualMachineRawConfig_create() isn't unsafe but rust_bindgen forces it to be seen
+    // as unsafe
+    let config = unsafe { AVirtualMachineRawConfig_create() };
+
+    info!("raw config created");
+
+    // SAFETY: config is the only reference to a valid object
+    unsafe {
+        AVirtualMachineRawConfig_setName(config, test_name.as_ptr());
+        AVirtualMachineRawConfig_setKernel(config, kernel_fd);
+        AVirtualMachineRawConfig_setProtectedVm(config, protected_vm);
+        AVirtualMachineRawConfig_setMemoryMiB(config, VM_MEMORY_MB);
+    }
+
+    let mut vm = std::ptr::null_mut();
+    let mut service = std::ptr::null_mut();
+
+    ensure!(
+        // SAFETY: &mut service is a valid pointer to *AVirtualizationService
+        unsafe { AVirtualizationService_create(&mut service, false) } == 0,
+        "AVirtualizationService_create failed"
+    );
+
+    scopeguard::defer! {
+        // SAFETY: service is a valid pointer to AVirtualizationService
+        unsafe { AVirtualizationService_destroy(service); }
+    }
+
+    ensure!(
+        // SAFETY: &mut vm is a valid pointer to *AVirtualMachine
+        unsafe {
+            AVirtualMachine_createRaw(
+                service, config, -1, // console_in
+                -1, // console_out
+                -1, // log
+                &mut vm,
+            )
+        } == 0,
+        "AVirtualMachine_createRaw failed"
+    );
+
+    scopeguard::defer! {
+        // SAFETY: vm is a valid pointer to AVirtualMachine
+        unsafe { AVirtualMachine_destroy(vm); }
+    }
+
+    info!("vm created");
+
+    let vm_type = if protected_vm { VmType::ProtectedVm } else { VmType::NonProtectedVm };
+
+    let listener_thread = std::thread::spawn(move || listen_from_guest(vm_type.port()));
+
+    // SAFETY: vm is the only reference to a valid object
+    unsafe {
+        AVirtualMachine_start(vm);
+    }
+
+    info!("VM started");
+
+    let mut vsock_stream = listener_thread.join().unwrap()?;
+    vsock_stream.set_read_timeout(Some(READ_TIMEOUT))?;
+    vsock_stream.set_write_timeout(Some(WRITE_TIMEOUT))?;
+
+    info!("client connected");
+
+    let request_data = vec![1, 2, 3, 4, 5];
+    let expected_data = vec![5, 4, 3, 2, 1];
+    let response = process_request(&mut vsock_stream, Request::Reverse(request_data))
+        .context("Failed to process request")?;
+    let Response::Reverse(reversed_data) = response else {
+        bail!("Expected Response::Reverse but was {response:?}");
+    };
+    ensure!(reversed_data == expected_data, "Expected {expected_data:?} but was {reversed_data:?}");
+
+    info!("request processed");
+
+    write_request(&mut vsock_stream, &ServiceVmRequest::Shutdown)
+        .context("Failed to send shutdown")?;
+
+    info!("shutdown sent");
+
+    let mut stop_reason = AVirtualMachineStopReason::AVIRTUAL_MACHINE_UNRECOGNISED;
+    ensure!(
+        // SAFETY: vm is the only reference to a valid object
+        unsafe { AVirtualMachine_waitForStop(vm, &STOP_TIMEOUT, &mut stop_reason) },
+        "AVirtualMachine_waitForStop failed"
+    );
+    assert_eq!(stop_reason, AVirtualMachineStopReason::AVIRTUAL_MACHINE_SHUTDOWN);
+
+    info!("stopped");
+
+    Ok(())
+}
+
+#[test]
+fn test_run_rialto_protected() -> Result<()> {
+    if hypervisor_props::is_protected_vm_supported()? {
+        run_vm(
+            "/data/local/tmp/rialto.bin", /* image_path */
+            c"test_rialto",               /* test_name */
+            true,                         /* protected_vm */
+        )
+    } else {
+        info!("pVMs are not supported on device. skipping test");
+        Ok(())
+    }
+}
+
+#[test]
+fn test_run_rialto_non_protected() -> Result<()> {
+    if hypervisor_props::is_vm_supported()? {
+        run_vm(
+            "/data/local/tmp/rialto.bin", /* image_path */
+            c"test_rialto",               /* test_name */
+            false,                        /* protected_vm */
+        )
+    } else {
+        info!("VMs are not supported on device. skipping test");
+        Ok(())
+    }
+}
+
+#[test]
+fn test_run_android16_rialto_protected() -> Result<()> {
+    if hypervisor_props::is_protected_vm_supported()? {
+        run_vm(
+            "/data/local/tmp/android16_rialto.bin", /* image_path */
+            c"android16_test_rialto",               /* test_name */
+            true,                                   /* protected_vm */
+        )
+    } else {
+        info!("pVMs are not supported on device. skipping test");
+        Ok(())
+    }
+}
+
+#[test]
+fn test_run_android16_rialto_non_protected() -> Result<()> {
+    if hypervisor_props::is_vm_supported()? {
+        run_vm(
+            "/data/local/tmp/android16_rialto.bin", /* image_path */
+            c"android16_test_rialto",               /* test_name */
+            false,                                  /* protected_vm */
+        )
+    } else {
+        info!("VMs are not supported on device. skipping test");
+        Ok(())
+    }
+}