Merge "Fix typo" into main
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java b/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
index 0673536..a6381ac 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -494,7 +494,6 @@
                 && Objects.equals(this.mPayloadConfigPath, other.mPayloadConfigPath)
                 && Objects.equals(this.mPayloadBinaryName, other.mPayloadBinaryName)
                 && Objects.equals(this.mPackageName, other.mPackageName)
-                && Objects.equals(this.mApkPath, other.mApkPath)
                 && Objects.equals(this.mOs, other.mOs);
     }
 
diff --git a/libs/libfdt/src/iterators.rs b/libs/libfdt/src/iterators.rs
index 7406164..e818c68 100644
--- a/libs/libfdt/src/iterators.rs
+++ b/libs/libfdt/src/iterators.rs
@@ -304,7 +304,7 @@
 }
 
 impl<'a> SubnodeIterator<'a> {
-    pub(crate) fn new(node: &'a FdtNode) -> Result<Self, FdtError> {
+    pub(crate) fn new(node: &FdtNode<'a>) -> Result<Self, FdtError> {
         let subnode = node.first_subnode()?;
 
         Ok(Self { subnode })
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index d90f5f0..8a4e251 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -468,7 +468,7 @@
     }
 
     /// Returns an iterator of subnodes
-    pub fn subnodes(&'a self) -> Result<SubnodeIterator<'a>> {
+    pub fn subnodes(&self) -> Result<SubnodeIterator<'a>> {
         SubnodeIterator::new(self)
     }
 
@@ -750,6 +750,14 @@
         FdtNode { fdt: self.fdt, offset: self.offset }
     }
 
+    /// Adds new subnodes to the given node.
+    pub fn add_subnodes(&mut self, names: &[&CStr]) -> Result<()> {
+        for name in names {
+            self.add_subnode_offset(name.to_bytes())?;
+        }
+        Ok(())
+    }
+
     /// Adds a new subnode to the given node and return it as a FdtNodeMut on success.
     pub fn add_subnode(&'a mut self, name: &CStr) -> Result<Self> {
         let offset = self.add_subnode_offset(name.to_bytes())?;
diff --git a/libs/libfdt/tests/api_test.rs b/libs/libfdt/tests/api_test.rs
index 08fb8a5..cafbf97 100644
--- a/libs/libfdt/tests/api_test.rs
+++ b/libs/libfdt/tests/api_test.rs
@@ -19,6 +19,7 @@
 use core::ffi::CStr;
 use cstr::cstr;
 use libfdt::{Fdt, FdtError, FdtNodeMut, Phandle};
+use std::collections::HashSet;
 use std::ffi::CString;
 use std::fs;
 use std::ops::Range;
@@ -451,6 +452,22 @@
 }
 
 #[test]
+fn node_mut_add_subnodes() {
+    let mut data = vec![0_u8; 1000];
+    let fdt = Fdt::create_empty_tree(&mut data).unwrap();
+
+    let mut root = fdt.root_mut().unwrap();
+    let names = [cstr!("a"), cstr!("b")];
+    root.add_subnodes(&names).unwrap();
+
+    let expected: HashSet<_> = names.into_iter().collect();
+    let subnodes = fdt.root().unwrap().subnodes().unwrap();
+    let names: HashSet<_> = subnodes.map(|node| node.name().unwrap()).collect();
+
+    assert_eq!(expected, names);
+}
+
+#[test]
 #[ignore] // Borrow checker test. Compilation success is sufficient.
 fn node_subnode_lifetime() {
     let data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
@@ -471,6 +488,28 @@
 
 #[test]
 #[ignore] // Borrow checker test. Compilation success is sufficient.
+fn node_subnodess_lifetime() {
+    let data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
+    let fdt = Fdt::from_slice(&data).unwrap();
+
+    let first_subnode_name = {
+        let first_subnode = {
+            let mut subnodes_iter = {
+                let root = fdt.root().unwrap();
+                root.subnodes().unwrap()
+                // Make root to be dropped
+            };
+            subnodes_iter.next().unwrap()
+            // Make subnodess_iter to be dropped
+        };
+        first_subnode.name()
+        // Make first_subnode to be dropped
+    };
+    assert_eq!(Ok(cstr!("node_a")), first_subnode_name);
+}
+
+#[test]
+#[ignore] // Borrow checker test. Compilation success is sufficient.
 fn node_descendants_lifetime() {
     let data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
     let fdt = Fdt::from_slice(&data).unwrap();
diff --git a/pvmfw/README.md b/pvmfw/README.md
index 795bb05..d7884fb 100644
--- a/pvmfw/README.md
+++ b/pvmfw/README.md
@@ -214,17 +214,19 @@
   that if matching properties are present in the VM device tree they contain the
   correct values.
 
-  One use case for this mechanism is passing the [public key of the
-  Secretkeeper][secretkeeper_key] HAL implementation to each VM.
+  Use-cases of VM reference DT include:
 
-<!--
-  TODO(b/319192461): Attach link explaining about Microdroid vendor partition
--->
+  - Passing the [public key of the Secretkeeper][secretkeeper_key] HAL
+    implementation to each VM.
+
+  - Passing the [vendor hashtree digest][vendor_hashtree_digest] to run
+    Microdroid with verified vendor image.
 
 [header]: src/config.rs
 [DTBO]: https://android.googlesource.com/platform/external/dtc/+/refs/heads/main/Documentation/dt-object-internal.txt
 [debug_policy]: ../docs/debug/README.md#debug-policy
 [secretkeeper_key]: https://android.googlesource.com/platform/system/secretkeeper/+/refs/heads/main/README.md#secretkeeper-public-key
+[vendor_hashtree_digest]: ../microdroid/README.md#verification-of-vendor-image
 
 #### Virtual Platform Boot Certificate Chain Handover
 
diff --git a/tests/benchmark/assets/vm_config.json b/tests/benchmark/assets/microdroid/vm_config.json
similarity index 100%
rename from tests/benchmark/assets/vm_config.json
rename to tests/benchmark/assets/microdroid/vm_config.json
diff --git a/tests/benchmark/assets/vm_config_io.json b/tests/benchmark/assets/microdroid/vm_config_io.json
similarity index 100%
rename from tests/benchmark/assets/vm_config_io.json
rename to tests/benchmark/assets/microdroid/vm_config_io.json
diff --git a/tests/benchmark/assets/vm_config_gki-android14-6.1.json b/tests/benchmark/assets/microdroid_gki-android14-6.1/vm_config.json
similarity index 100%
rename from tests/benchmark/assets/vm_config_gki-android14-6.1.json
rename to tests/benchmark/assets/microdroid_gki-android14-6.1/vm_config.json
diff --git a/tests/benchmark/assets/microdroid_gki-android14-6.1/vm_config_io.json b/tests/benchmark/assets/microdroid_gki-android14-6.1/vm_config_io.json
new file mode 100644
index 0000000..34c204e
--- /dev/null
+++ b/tests/benchmark/assets/microdroid_gki-android14-6.1/vm_config_io.json
@@ -0,0 +1,15 @@
+{
+  "os": {
+    "name": "microdroid_gki-android14-6.1"
+  },
+  "task": {
+    "type": "microdroid_launcher",
+    "command": "MicrodroidBenchmarkNativeLib.so"
+  },
+  "apexes": [
+    {
+      "name": "com.android.virt"
+    }
+  ],
+  "export_tombstones": true
+}
diff --git a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
index e406172..e0de9b3 100644
--- a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
+++ b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
@@ -66,6 +66,7 @@
 import java.io.Writer;
 import java.nio.file.Files;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -91,12 +92,23 @@
     private static final String MICRODROID_IMG_PREFIX = "microdroid_";
     private static final String MICRODROID_IMG_SUFFIX = ".img";
 
-    @Parameterized.Parameters(name = "protectedVm={0}")
-    public static Object[] protectedVmConfigs() {
-        return new Object[] {false, true};
+    @Parameterized.Parameters(name = "protectedVm={0},gki={1}")
+    public static Collection<Object[]> params() {
+        List<Object[]> ret = new ArrayList<>();
+        ret.add(new Object[] {true /* protectedVm */, null /* use microdroid kernel */});
+        ret.add(new Object[] {false /* protectedVm */, null /* use microdroid kernel */});
+        for (String gki : SUPPORTED_GKI_VERSIONS) {
+            ret.add(new Object[] {true /* protectedVm */, gki});
+            ret.add(new Object[] {false /* protectedVm */, gki});
+        }
+        return ret;
     }
 
-    @Parameterized.Parameter public boolean mProtectedVm;
+    @Parameterized.Parameter(0)
+    public boolean mProtectedVm;
+
+    @Parameterized.Parameter(1)
+    public String mGki;
 
     private final MetricsProcessor mMetricsProcessor = new MetricsProcessor(METRIC_NAME_PREFIX);
 
@@ -119,7 +131,7 @@
     public void setup() throws IOException {
         grantPermission(VirtualMachine.MANAGE_VIRTUAL_MACHINE_PERMISSION);
         grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
-        prepareTestSetup(mProtectedVm, null /* gki */);
+        prepareTestSetup(mProtectedVm, mGki);
         setMaxPerformanceTaskProfile();
         mInstrumentation = getInstrumentation();
     }
@@ -240,62 +252,31 @@
             throws VirtualMachineException, InterruptedException, IOException {
         runBootTimeTest(
                 "test_vm_boot_time",
-                "assets/vm_config.json",
+                "assets/" + os() + "/vm_config.json",
                 /* fullDebug */ false,
                 (builder) -> builder.setCpuTopology(CPU_TOPOLOGY_ONE_CPU));
     }
-
-    @Test
-    public void testMicrodroidGkiBootTime()
-            throws VirtualMachineException, InterruptedException, IOException {
-        runBootTimeTest(
-                "test_vm_boot_time",
-                "assets/vm_config_gki-android14-6.1.json",
-                /* reportDetailed */ false,
-                (builder) -> builder.setCpuTopology(CPU_TOPOLOGY_ONE_CPU));
-    }
-
     @Test
     public void testMicrodroidHostCpuTopologyBootTime()
             throws VirtualMachineException, InterruptedException, IOException {
         runBootTimeTest(
                 "test_vm_boot_time_host_topology",
-                "assets/vm_config.json",
+                "assets/" + os() + "/vm_config.json",
                 /* fullDebug */ false,
                 (builder) -> builder.setCpuTopology(CPU_TOPOLOGY_MATCH_HOST));
     }
 
     @Test
-    public void testMicrodroidGkiHostCpuTopologyBootTime()
-            throws VirtualMachineException, InterruptedException, IOException {
-        runBootTimeTest(
-                "test_vm_boot_time_host_topology",
-                "assets/vm_config_gki-android14-6.1.json",
-                /* reportDetailed */ false,
-                (builder) -> builder.setCpuTopology(CPU_TOPOLOGY_MATCH_HOST));
-    }
-
-    @Test
     public void testMicrodroidDebugBootTime()
             throws VirtualMachineException, InterruptedException, IOException {
         runBootTimeTest(
                 "test_vm_boot_time_debug",
-                "assets/vm_config.json",
+                "assets/" + os() + "/vm_config.json",
                 /* fullDebug */ true,
                 (builder) -> builder);
     }
 
     @Test
-    public void testMicrodroidGkiDebugBootTime()
-            throws VirtualMachineException, InterruptedException, IOException {
-        runBootTimeTest(
-                "test_vm_boot_time_debug",
-                "assets/vm_config_gki-android14-6.1.json",
-                /* reportDetailed */ true,
-                (builder) -> builder);
-    }
-
-    @Test
     public void testMicrodroidDebugBootTime_withVendorPartition() throws Exception {
         assume().withMessage(
                         "Cuttlefish doesn't support device tree under"
@@ -318,7 +299,7 @@
                 new File("/data/local/tmp/microdroid-bench/microdroid_vendor_image.img");
         runBootTimeTest(
                 "test_vm_boot_time_debug_with_vendor_partition",
-                "assets/vm_config.json",
+                "assets/" + os() + "/vm_config.json",
                 /* fullDebug */ true,
                 (builder) -> builder.setVendorDiskImage(vendorDiskImage));
     }
@@ -347,7 +328,7 @@
     @Test
     public void testVsockTransferFromHostToVM() throws Exception {
         VirtualMachineConfig config =
-                newVmConfigBuilderWithPayloadConfig("assets/vm_config_io.json")
+                newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config_io.json")
                         .setDebugLevel(DEBUG_LEVEL_NONE)
                         .build();
         List<Double> transferRates = new ArrayList<>(IO_TEST_TRIAL_COUNT);
@@ -373,7 +354,7 @@
 
     private void testVirtioBlkReadRate(boolean isRand) throws Exception {
         VirtualMachineConfig config =
-                newVmConfigBuilderWithPayloadConfig("assets/vm_config_io.json")
+                newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config_io.json")
                         .setDebugLevel(DEBUG_LEVEL_NONE)
                         .build();
         List<Double> readRates = new ArrayList<>(IO_TEST_TRIAL_COUNT);
@@ -519,7 +500,7 @@
     public void testMemoryUsage() throws Exception {
         final String vmName = "test_vm_mem_usage";
         VirtualMachineConfig config =
-                newVmConfigBuilderWithPayloadConfig("assets/vm_config_io.json")
+                newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config_io.json")
                         .setDebugLevel(DEBUG_LEVEL_NONE)
                         .setMemoryBytes(256 * ONE_MEBI)
                         .build();
@@ -605,7 +586,7 @@
     public void testMemoryReclaim() throws Exception {
         final String vmName = "test_vm_mem_reclaim";
         VirtualMachineConfig config =
-                newVmConfigBuilderWithPayloadConfig("assets/vm_config_io.json")
+                newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config_io.json")
                         .setDebugLevel(DEBUG_LEVEL_NONE)
                         .setMemoryBytes(256 * ONE_MEBI)
                         .build();
@@ -830,7 +811,7 @@
     @Test
     public void testVmKillTime() throws Exception {
         VirtualMachineConfig config =
-                newVmConfigBuilderWithPayloadConfig("assets/vm_config_io.json")
+                newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config_io.json")
                         .setDebugLevel(DEBUG_LEVEL_NONE)
                         .build();
         List<Double> vmKillTime = new ArrayList<>(TEST_TRIAL_COUNT);
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 6471fed..33d41ab 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -616,9 +616,12 @@
                     .isFalse();
         }
 
+        // Changes that were incompatible but are currently compatible, but not guaranteed to be
+        // so in the API spec.
+        assertConfigCompatible(baseline, newBaselineBuilder().setApkPath("/different")).isTrue();
+
         // Changes that are currently incompatible for ease of implementation, but this might change
         // in the future.
-        assertConfigCompatible(baseline, newBaselineBuilder().setApkPath("/different")).isFalse();
         assertConfigCompatible(baseline, newBaselineBuilder().setEncryptedStorageBytes(100_000))
                 .isFalse();