Validate setOs and --gki when creating a VM

As config files can specify os, VirtualMachineConfig.setOs() and --gki
option in the vm tool will work only for binary payloads. This change
validates those so users don't accidentally use both os and config.

Bug: 302465542
Test: atest MicrodroidHostTests MicrodroidTests
Test: manually invoke vm tool
Change-Id: I122de63d32ab7414af780783fe758e8b34b5c649
diff --git a/javalib/api/test-current.txt b/javalib/api/test-current.txt
index 34837a3..958005f 100644
--- a/javalib/api/test-current.txt
+++ b/javalib/api/test-current.txt
@@ -7,7 +7,7 @@
   }
 
   public final class VirtualMachineConfig {
-    method @FlaggedApi("RELEASE_AVF_ENABLE_VENDOR_MODULES") @NonNull public String getOs();
+    method @FlaggedApi("RELEASE_AVF_ENABLE_VENDOR_MODULES") @Nullable public String getOs();
     method @Nullable public String getPayloadConfigPath();
     method public boolean isVmConsoleInputSupported();
   }
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java b/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
index cdc8f02..ad36208 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -174,7 +174,8 @@
 
     @Nullable private final File mVendorDiskImage;
 
-    private final String mOs;
+    /** OS name of the VM using payload binaries. null if the VM uses a payload config file. */
+    @Nullable private final String mOs;
 
     private VirtualMachineConfig(
             @Nullable String packageName,
@@ -189,7 +190,7 @@
             boolean vmOutputCaptured,
             boolean vmConsoleInputSupported,
             @Nullable File vendorDiskImage,
-            @NonNull String os) {
+            @Nullable String os) {
         // This is only called from Builder.build(); the builder handles parameter validation.
         mPackageName = packageName;
         mApkPath = apkPath;
@@ -458,14 +459,14 @@
     }
 
     /**
-     * Returns the OS of the VM.
+     * Returns the OS of the VM using a payload binary. Returns null if the VM uses payload config.
      *
      * @see Builder#setOs
      * @hide
      */
     @TestApi
     @FlaggedApi("RELEASE_AVF_ENABLE_VENDOR_MODULES")
-    @NonNull
+    @Nullable
     public String getOs() {
         return mOs;
     }
@@ -632,7 +633,7 @@
         private boolean mVmOutputCaptured = false;
         private boolean mVmConsoleInputSupported = false;
         @Nullable private File mVendorDiskImage;
-        private String mOs = DEFAULT_OS;
+        @Nullable private String mOs;
 
         /**
          * Creates a builder for the given context.
@@ -672,15 +673,25 @@
                 throw new IllegalStateException("apkPath or packageName must be specified");
             }
 
+            String os = null;
             if (mPayloadBinaryName == null) {
                 if (mPayloadConfigPath == null) {
                     throw new IllegalStateException("setPayloadBinaryName must be called");
                 }
+                if (mOs != null) {
+                    throw new IllegalStateException(
+                            "setPayloadConfigPath and setOs may not both be called");
+                }
             } else {
                 if (mPayloadConfigPath != null) {
                     throw new IllegalStateException(
                             "setPayloadBinaryName and setPayloadConfigPath may not both be called");
                 }
+                if (mOs != null) {
+                    os = mOs;
+                } else {
+                    os = DEFAULT_OS;
+                }
             }
 
             if (!mProtectedVmSet) {
@@ -708,7 +719,7 @@
                     mVmOutputCaptured,
                     mVmConsoleInputSupported,
                     mVendorDiskImage,
-                    mOs);
+                    os);
         }
 
         /**
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 6314c25..e406172 100644
--- a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
+++ b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
@@ -134,8 +134,7 @@
     private boolean canBootMicrodroidWithMemory(int mem)
             throws VirtualMachineException, InterruptedException, IOException {
         VirtualMachineConfig normalConfig =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidIdleNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidIdleNativeLib.so")
                         .setDebugLevel(DEBUG_LEVEL_NONE)
                         .setMemoryBytes(mem * ONE_MEBI)
                         .build();
@@ -213,8 +212,7 @@
         BootTimeStats stats = new BootTimeStats(trialCount);
         for (int i = 0; i < trialCount; i++) {
             VirtualMachineConfig.Builder builder =
-                    newVmConfigBuilder()
-                            .setPayloadConfigPath(payloadConfig)
+                    newVmConfigBuilderWithPayloadBinary("MicrodroidIdleNativeLib.so")
                             .setMemoryBytes(256 * ONE_MEBI)
                             .setDebugLevel(DEBUG_LEVEL_NONE);
             if (fullDebug) {
@@ -349,8 +347,7 @@
     @Test
     public void testVsockTransferFromHostToVM() throws Exception {
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadConfigPath("assets/vm_config_io.json")
+                newVmConfigBuilderWithPayloadConfig("assets/vm_config_io.json")
                         .setDebugLevel(DEBUG_LEVEL_NONE)
                         .build();
         List<Double> transferRates = new ArrayList<>(IO_TEST_TRIAL_COUNT);
@@ -376,8 +373,7 @@
 
     private void testVirtioBlkReadRate(boolean isRand) throws Exception {
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadConfigPath("assets/vm_config_io.json")
+                newVmConfigBuilderWithPayloadConfig("assets/vm_config_io.json")
                         .setDebugLevel(DEBUG_LEVEL_NONE)
                         .build();
         List<Double> readRates = new ArrayList<>(IO_TEST_TRIAL_COUNT);
@@ -523,8 +519,7 @@
     public void testMemoryUsage() throws Exception {
         final String vmName = "test_vm_mem_usage";
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadConfigPath("assets/vm_config_io.json")
+                newVmConfigBuilderWithPayloadConfig("assets/vm_config_io.json")
                         .setDebugLevel(DEBUG_LEVEL_NONE)
                         .setMemoryBytes(256 * ONE_MEBI)
                         .build();
@@ -610,8 +605,7 @@
     public void testMemoryReclaim() throws Exception {
         final String vmName = "test_vm_mem_reclaim";
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadConfigPath("assets/vm_config_io.json")
+                newVmConfigBuilderWithPayloadConfig("assets/vm_config_io.json")
                         .setDebugLevel(DEBUG_LEVEL_NONE)
                         .setMemoryBytes(256 * ONE_MEBI)
                         .build();
@@ -730,8 +724,7 @@
         final int NUM_REQUESTS = 10_000;
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setDebugLevel(DEBUG_LEVEL_NONE)
                         .build();
 
@@ -779,8 +772,7 @@
         final int NUM_REQUESTS = 10_000;
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setDebugLevel(DEBUG_LEVEL_NONE)
                         .build();
 
@@ -838,8 +830,7 @@
     @Test
     public void testVmKillTime() throws Exception {
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadConfigPath("assets/vm_config_io.json")
+                newVmConfigBuilderWithPayloadConfig("assets/vm_config_io.json")
                         .setDebugLevel(DEBUG_LEVEL_NONE)
                         .build();
         List<Double> vmKillTime = new ArrayList<>(TEST_TRIAL_COUNT);
diff --git a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
index c2244bc..15e175b 100644
--- a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
+++ b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
@@ -112,7 +112,7 @@
 
     private Context mCtx;
     private boolean mProtectedVm;
-    private String mOs;
+    private String mGki;
 
     protected Context getContext() {
         return mCtx;
@@ -122,8 +122,17 @@
         return mCtx.getSystemService(VirtualMachineManager.class);
     }
 
-    public VirtualMachineConfig.Builder newVmConfigBuilder() {
-        return new VirtualMachineConfig.Builder(mCtx).setProtectedVm(mProtectedVm).setOs(mOs);
+    public VirtualMachineConfig.Builder newVmConfigBuilderWithPayloadConfig(String configPath) {
+        return new VirtualMachineConfig.Builder(mCtx)
+                .setProtectedVm(mProtectedVm)
+                .setPayloadConfigPath(configPath);
+    }
+
+    public VirtualMachineConfig.Builder newVmConfigBuilderWithPayloadBinary(String binaryPath) {
+        return new VirtualMachineConfig.Builder(mCtx)
+                .setProtectedVm(mProtectedVm)
+                .setOs(os())
+                .setPayloadBinaryName(binaryPath);
     }
 
     protected final boolean isProtectedVm() {
@@ -131,7 +140,7 @@
     }
 
     protected final String os() {
-        return mOs;
+        return mGki != null ? "microdroid_gki-" + mGki : "microdroid";
     }
 
     /**
@@ -155,7 +164,7 @@
                 .isTrue();
 
         mProtectedVm = protectedVm;
-        mOs = gki != null ? "microdroid_gki-" + gki : "microdroid";
+        mGki = gki;
 
         int capabilities = getVirtualMachineManager().getCapabilities();
         if (protectedVm) {
@@ -169,8 +178,8 @@
         }
 
         try {
-            assume().withMessage("Skip where requested OS \"" + mOs + "\" isn't supported")
-                    .that(mOs)
+            assume().withMessage("Skip where requested OS \"" + os() + "\" isn't supported")
+                    .that(os())
                     .isIn(getVirtualMachineManager().getSupportedOSList());
         } catch (VirtualMachineException e) {
             Log.e(TAG, "Error getting supported OS list", e);
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 6605f89..6471fed 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -170,8 +170,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setMemoryBytes(minMemoryRequired())
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .setCpuTopology(cpuTopology)
@@ -217,8 +216,7 @@
         // For most of our tests we use a debug VM so failures can be diagnosed.
         // But we do need non-debug VMs to work, so run one.
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setMemoryBytes(minMemoryRequired())
                         .setDebugLevel(DEBUG_LEVEL_NONE)
                         .setVmOutputCaptured(false)
@@ -244,8 +242,7 @@
         revokePermission(VirtualMachine.MANAGE_VIRTUAL_MACHINE_PERMISSION);
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setMemoryBytes(minMemoryRequired())
                         .build();
 
@@ -263,8 +260,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setMemoryBytes(minMemoryRequired())
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
@@ -292,8 +288,7 @@
     @CddTest(requirements = {"9.17/C-1-1"})
     public void autoCloseVmDescriptor() throws Exception {
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
         VirtualMachine vm = forceCreateNewVirtualMachine("test_vm", config);
@@ -322,8 +317,7 @@
     @CddTest(requirements = {"9.17/C-1-1"})
     public void vmDescriptorClosedOnImport() throws Exception {
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
         VirtualMachine vm = forceCreateNewVirtualMachine("test_vm", config);
@@ -348,8 +342,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setMemoryBytes(minMemoryRequired())
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
@@ -397,8 +390,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setMemoryBytes(minMemoryRequired())
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
@@ -436,8 +428,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setMemoryBytes(minMemoryRequired())
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
@@ -529,7 +520,7 @@
         assertThat(maximal.isEncryptedStorageEnabled()).isTrue();
         assertThat(maximal.getEncryptedStorageBytes()).isEqualTo(1_000_000);
         assertThat(maximal.isVmOutputCaptured()).isEqualTo(true);
-        assertThat(maximal.getOs()).isEqualTo("microdroid");
+        assertThat(maximal.getOs()).isNull();
 
         assertThat(minimal.isCompatibleWith(maximal)).isFalse();
         assertThat(minimal.isCompatibleWith(minimal)).isTrue();
@@ -544,14 +535,15 @@
     @Test
     @CddTest(requirements = {"9.17/C-1-1"})
     public void vmConfigBuilderValidationTests() {
-        VirtualMachineConfig.Builder builder = newVmConfigBuilder();
+        VirtualMachineConfig.Builder builder =
+                new VirtualMachineConfig.Builder(getContext()).setProtectedVm(mProtectedVm);
 
         // All your null are belong to me.
         assertThrows(NullPointerException.class, () -> new VirtualMachineConfig.Builder(null));
         assertThrows(NullPointerException.class, () -> builder.setApkPath(null));
         assertThrows(NullPointerException.class, () -> builder.setPayloadConfigPath(null));
         assertThrows(NullPointerException.class, () -> builder.setPayloadBinaryName(null));
-        assertThrows(NullPointerException.class, () -> builder.setPayloadConfigPath(null));
+        assertThrows(NullPointerException.class, () -> builder.setOs(null));
 
         // Individual property checks.
         assertThrows(
@@ -574,20 +566,28 @@
         assertThat(e).hasMessageThat().contains("setProtectedVm must be called");
 
         VirtualMachineConfig.Builder captureOutputOnNonDebuggable =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("binary.so")
+                newVmConfigBuilderWithPayloadBinary("binary.so")
                         .setDebugLevel(VirtualMachineConfig.DEBUG_LEVEL_NONE)
                         .setVmOutputCaptured(true);
         e = assertThrows(IllegalStateException.class, () -> captureOutputOnNonDebuggable.build());
         assertThat(e).hasMessageThat().contains("debug level must be FULL to capture output");
 
         VirtualMachineConfig.Builder captureInputOnNonDebuggable =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("binary.so")
+                newVmConfigBuilderWithPayloadBinary("binary.so")
                         .setDebugLevel(VirtualMachineConfig.DEBUG_LEVEL_NONE)
                         .setVmConsoleInputSupported(true);
         e = assertThrows(IllegalStateException.class, () -> captureInputOnNonDebuggable.build());
         assertThat(e).hasMessageThat().contains("debug level must be FULL to use console input");
+
+        VirtualMachineConfig.Builder specifyBothOsAndConfig =
+                new VirtualMachineConfig.Builder(getContext())
+                        .setPayloadConfigPath("config/path")
+                        .setProtectedVm(mProtectedVm)
+                        .setOs("microdroid");
+        e = assertThrows(IllegalStateException.class, () -> specifyBothOsAndConfig.build());
+        assertThat(e)
+                .hasMessageThat()
+                .contains("setPayloadConfigPath and setOs may not both be called");
     }
 
     @Test
@@ -658,7 +658,7 @@
     }
 
     private VirtualMachineConfig.Builder newBaselineBuilder() {
-        return newVmConfigBuilder().setPayloadBinaryName("binary.so").setApkPath("/apk/path");
+        return newVmConfigBuilderWithPayloadBinary("binary.so").setApkPath("/apk/path");
     }
 
     private BooleanSubject assertConfigCompatible(
@@ -669,8 +669,7 @@
     @Test
     @CddTest(requirements = {"9.17/C-1-1"})
     public void vmUnitTests() throws Exception {
-        VirtualMachineConfig.Builder builder =
-                newVmConfigBuilder().setPayloadBinaryName("binary.so");
+        VirtualMachineConfig.Builder builder = newVmConfigBuilderWithPayloadBinary("binary.so");
         VirtualMachineConfig config = builder.build();
         VirtualMachine vm = forceCreateNewVirtualMachine("vm_name", config);
 
@@ -702,8 +701,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setMemoryBytes(minMemoryRequired())
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
@@ -750,8 +748,7 @@
         final Context ctx = getContext().createDeviceProtectedStorageContext();
         final int userId = ctx.getUserId();
         final VirtualMachineManager vmm = ctx.getSystemService(VirtualMachineManager.class);
-        VirtualMachineConfig config =
-                newVmConfigBuilder().setPayloadBinaryName("binary.so").build();
+        VirtualMachineConfig config = newVmConfigBuilderWithPayloadBinary("binary.so").build();
         try {
             VirtualMachine vm = vmm.create("vm-name", config);
             // TODO(b/261430346): what about non-primary user?
@@ -769,8 +766,7 @@
         final Context ctx = getContext().createCredentialProtectedStorageContext();
         final int userId = ctx.getUserId();
         final VirtualMachineManager vmm = ctx.getSystemService(VirtualMachineManager.class);
-        VirtualMachineConfig config =
-                newVmConfigBuilder().setPayloadBinaryName("binary.so").build();
+        VirtualMachineConfig config = newVmConfigBuilderWithPayloadBinary("binary.so").build();
         try {
             VirtualMachine vm = vmm.create("vm-name", config);
             // TODO(b/261430346): what about non-primary user?
@@ -800,8 +796,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadConfigPath("assets/" + os() + "/vm_config.json")
+                newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config.json")
                         .setMemoryBytes(minMemoryRequired())
                         .build();
 
@@ -823,8 +818,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setMemoryBytes(minMemoryRequired())
                         .build();
 
@@ -851,8 +845,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidExitNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidExitNativeLib.so")
                         .setMemoryBytes(minMemoryRequired())
                         .build();
 
@@ -884,8 +877,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setApkPath(getContext().getPackageCodePath())
                         .setMemoryBytes(minMemoryRequired())
                         .setDebugLevel(DEBUG_LEVEL_FULL)
@@ -922,8 +914,7 @@
 
         grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadConfigPath("assets/" + os() + "/vm_config_extra_apk.json")
+                newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config_extra_apk.json")
                         .setMemoryBytes(minMemoryRequired())
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
@@ -944,8 +935,7 @@
     public void bootFailsWhenLowMem() throws Exception {
         for (int memMib : new int[]{ 10, 20, 40 }) {
             VirtualMachineConfig lowMemConfig =
-                    newVmConfigBuilder()
-                            .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                    newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                             .setMemoryBytes(memMib)
                             .setDebugLevel(DEBUG_LEVEL_NONE)
                             .setVmOutputCaptured(false)
@@ -995,8 +985,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig.Builder builder =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setDebugLevel(fromLevel)
                         .setVmOutputCaptured(false);
         VirtualMachineConfig normalConfig = builder.build();
@@ -1067,8 +1056,7 @@
 
         grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
         VirtualMachineConfig normalConfig =
-                newVmConfigBuilder()
-                        .setPayloadConfigPath("assets/" + os() + "/vm_config.json")
+                newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config.json")
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
         forceCreateNewVirtualMachine("test_vm_a", normalConfig);
@@ -1094,8 +1082,7 @@
 
         grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
         VirtualMachineConfig normalConfig =
-                newVmConfigBuilder()
-                        .setPayloadConfigPath("assets/" + os() + "/vm_config.json")
+                newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config.json")
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
         forceCreateNewVirtualMachine("test_vm", normalConfig);
@@ -1109,17 +1096,13 @@
     }
 
     @Test
-    @CddTest(requirements = {
-            "9.17/C-1-1",
-            "9.17/C-2-7"
-    })
+    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-7"})
     public void bccIsSuperficiallyWellFormed() throws Exception {
         assumeSupportedDevice();
 
         grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
         VirtualMachineConfig normalConfig =
-                newVmConfigBuilder()
-                        .setPayloadConfigPath("assets/" + os() + "/vm_config.json")
+                newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config.json")
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
         VirtualMachine vm = forceCreateNewVirtualMachine("bcc_vm", normalConfig);
@@ -1163,8 +1146,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
         forceCreateNewVirtualMachine("test_vm", config);
@@ -1217,8 +1199,7 @@
 
     private RandomAccessFile prepareInstanceImage(String vmName) throws Exception {
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
 
@@ -1277,8 +1258,7 @@
     public void bootFailsWhenConfigIsInvalid() throws Exception {
         grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
         VirtualMachineConfig normalConfig =
-                newVmConfigBuilder()
-                        .setPayloadConfigPath("assets/" + os() + "/vm_config_no_task.json")
+                newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config_no_task.json")
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
         forceCreateNewVirtualMachine("test_vm_invalid_config", normalConfig);
@@ -1292,7 +1272,7 @@
     @Test
     public void bootFailsWhenBinaryNameIsInvalid() throws Exception {
         VirtualMachineConfig.Builder builder =
-                newVmConfigBuilder().setPayloadBinaryName("DoesNotExist.so");
+                newVmConfigBuilderWithPayloadBinary("DoesNotExist.so");
         VirtualMachineConfig normalConfig = builder.setDebugLevel(DEBUG_LEVEL_FULL).build();
         forceCreateNewVirtualMachine("test_vm_invalid_binary_path", normalConfig);
 
@@ -1329,8 +1309,7 @@
     @Test
     public void bootFailsWhenBinaryIsMissingEntryFunction() throws Exception {
         VirtualMachineConfig normalConfig =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidEmptyNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidEmptyNativeLib.so")
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .setVmOutputCaptured(true)
                         .build();
@@ -1342,8 +1321,7 @@
     @Test
     public void bootFailsWhenBinaryTriesToLinkAgainstPrivateLibs() throws Exception {
         VirtualMachineConfig normalConfig =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidPrivateLinkingNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidPrivateLinkingNativeLib.so")
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .setVmOutputCaptured(true)
                         .build();
@@ -1355,7 +1333,7 @@
     @Test
     public void sameInstancesShareTheSameVmObject() throws Exception {
         VirtualMachineConfig config =
-                newVmConfigBuilder().setPayloadBinaryName("MicrodroidTestNativeLib.so").build();
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so").build();
 
         VirtualMachine vm = forceCreateNewVirtualMachine("test_vm", config);
         VirtualMachine vm2 = getVirtualMachineManager().get("test_vm");
@@ -1374,8 +1352,7 @@
         // Arrange
         grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadConfigPath("assets/" + os() + "/vm_config.json")
+                newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config.json")
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
         String vmNameOrig = "test_vm_orig";
@@ -1415,8 +1392,7 @@
             throws Exception {
         // Arrange
         VirtualMachineConfig.Builder builder =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setDebugLevel(DEBUG_LEVEL_FULL);
         if (encryptedStoreEnabled) {
             builder.setEncryptedStorageBytes(4_000_000);
@@ -1472,8 +1448,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setMemoryBytes(minMemoryRequired())
                         .setEncryptedStorageBytes(4_000_000)
                         .setDebugLevel(DEBUG_LEVEL_FULL)
@@ -1496,8 +1471,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setMemoryBytes(minMemoryRequired())
                         .setEncryptedStorageBytes(4_000_000)
                         .setDebugLevel(DEBUG_LEVEL_FULL)
@@ -1557,8 +1531,7 @@
         assumeSupportedDevice();
 
         final VirtualMachineConfig vmConfig =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setMemoryBytes(minMemoryRequired())
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
@@ -1583,8 +1556,7 @@
         assumeFeatureEnabled(VirtualMachineManager.FEATURE_MULTI_TENANT);
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setMemoryBytes(minMemoryRequired())
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
@@ -1606,8 +1578,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setMemoryBytes(minMemoryRequired())
                         .setEncryptedStorageBytes(4_000_000)
                         .setDebugLevel(DEBUG_LEVEL_FULL)
@@ -1643,8 +1614,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setMemoryBytes(minMemoryRequired())
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
@@ -1776,8 +1746,7 @@
         assumeTrue("Not supported on GKI kernels", mGki == null);
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .setVmConsoleInputSupported(true)
                         .setVmOutputCaptured(true)
@@ -1833,8 +1802,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
 
@@ -1867,8 +1835,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .setEncryptedStorageBytes(1_000_000)
                         .build();
@@ -2024,8 +1991,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig vmConfig =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setMemoryBytes(minMemoryRequired())
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
@@ -2068,8 +2034,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig vmConfig =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
         VirtualMachine vm = forceCreateNewVirtualMachine("test_vm_data_mount", vmConfig);
@@ -2094,8 +2059,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig vmConfig =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .setEncryptedStorageBytes(4_000_000)
                         .build();
@@ -2149,8 +2113,7 @@
         File vendorDiskImage =
                 new File("/data/local/tmp/cts/microdroid/test_microdroid_vendor_image.img");
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setVendorDiskImage(vendorDiskImage)
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
@@ -2187,8 +2150,7 @@
         File vendorDiskImage =
                 new File("/data/local/tmp/cts/microdroid/test_microdroid_vendor_image.img");
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setVendorDiskImage(vendorDiskImage)
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
@@ -2226,8 +2188,7 @@
                 new File(
                         "/data/local/tmp/cts/microdroid/test_microdroid_vendor_image_unsigned.img");
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setVendorDiskImage(unsignedVendorDiskImage)
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
@@ -2242,8 +2203,7 @@
         assumeSupportedDevice();
 
         VirtualMachineConfig config =
-                newVmConfigBuilder()
-                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
                         .setDebugLevel(DEBUG_LEVEL_FULL)
                         .build();
 
diff --git a/vm/src/run.rs b/vm/src/run.rs
index 6ac141d..cfc5454 100644
--- a/vm/src/run.rs
+++ b/vm/src/run.rs
@@ -109,6 +109,9 @@
         if config.payload_binary_name.is_some() {
             bail!("Only one of --config-path or --payload-binary-name can be defined")
         }
+        if config.microdroid.gki().is_some() {
+            bail!("--gki cannot be defined with --config-path. Use 'os' field in the config file")
+        }
         Payload::ConfigPath(config_path)
     } else if let Some(payload_binary_name) = config.payload_binary_name {
         let os_name = if let Some(ver) = config.microdroid.gki() {