Initial work to make VM config file optional

Modify VirtualMachineAppConfig to allow configPath to be omitted;
instead a subset of the available config options can be specified
directly.

Modify VS to map the config options to the Metadata proto file.

At this stage nothing ever sets the payload config directly, and
Microdroid would reject it if it received it, but this at least
establishes the plumbing.

Bug: 243513572
Test: atest MicrodroidTests
Change-Id: I596384abf6e3bbbccd8934ba28fa3a85faa51b56
diff --git a/compos/common/compos_client.rs b/compos/common/compos_client.rs
index 49396d7..7327df7 100644
--- a/compos/common/compos_client.rs
+++ b/compos/common/compos_client.rs
@@ -23,7 +23,7 @@
 };
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
     IVirtualizationService::IVirtualizationService,
-    VirtualMachineAppConfig::{DebugLevel::DebugLevel, VirtualMachineAppConfig},
+    VirtualMachineAppConfig::{DebugLevel::DebugLevel, Payload::Payload, VirtualMachineAppConfig},
     VirtualMachineConfig::VirtualMachineConfig,
 };
 use anyhow::{bail, Context, Result};
@@ -122,7 +122,7 @@
             apk: Some(apk_fd),
             idsig: Some(idsig_fd),
             instanceImage: Some(instance_fd),
-            configPath: config_path,
+            payload: Payload::ConfigPath(config_path),
             debugLevel: debug_level,
             extraIdsigs: extra_idsigs,
             protectedVm: protected_vm,
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java b/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
index 4ecd942..63a3f43 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -222,7 +222,7 @@
     /* package */ VirtualMachineAppConfig toParcel() throws FileNotFoundException {
         VirtualMachineAppConfig parcel = new VirtualMachineAppConfig();
         parcel.apk = ParcelFileDescriptor.open(new File(mApkPath), MODE_READ_ONLY);
-        parcel.configPath = mPayloadConfigPath;
+        parcel.payload = VirtualMachineAppConfig.Payload.configPath(mPayloadConfigPath);
         switch (mDebugLevel) {
             case NONE:
                 parcel.debugLevel = VirtualMachineAppConfig.DebugLevel.NONE;
diff --git a/microdroid/payload/metadata.cc b/microdroid/payload/metadata.cc
index 07083e9..fd07bdd 100644
--- a/microdroid/payload/metadata.cc
+++ b/microdroid/payload/metadata.cc
@@ -40,7 +40,7 @@
     }
     size = be32toh(*reinterpret_cast<uint32_t*>(content.data()));
     if (content.size() < length_prefix_bytes + size) {
-        return Error() << "Invalid metadata: size(" << size << ") mimatches to the content size("
+        return Error() << "Invalid metadata: size(" << size << ") doesn't match content size("
                        << content.size() - length_prefix_bytes << ")";
     }
     content = content.substr(length_prefix_bytes, size);
diff --git a/microdroid/payload/metadata.proto b/microdroid/payload/metadata.proto
index 2e92f55..229d03f 100644
--- a/microdroid/payload/metadata.proto
+++ b/microdroid/payload/metadata.proto
@@ -26,7 +26,11 @@
 
   ApkPayload apk = 3;
 
-  string payload_config_path = 4;
+  oneof payload {
+    // Path to JSON config file inside the APK.
+    string config_path = 4;
+    PayloadConfig config = 5;
+  }
 }
 
 message ApexPayload {
@@ -58,3 +62,18 @@
 
   string idsig_partition_name = 3;
 }
+
+message PayloadConfig {
+  // Required.
+  // Path to the payload binary file inside the APK.
+  string payload_binary_path = 1;
+
+  // Required.
+  // Whether tombstones from crashes inside the VM should be exported to the host.
+  bool export_tombstones = 2;
+
+  // Optional.
+  // Arguments to be passed to the payload.
+  // TODO(b/249064104): Remove this
+  repeated string args = 3;
+}
diff --git a/microdroid/payload/metadata/src/lib.rs b/microdroid/payload/metadata/src/lib.rs
index eb9d90d..bfbec60 100644
--- a/microdroid/payload/metadata/src/lib.rs
+++ b/microdroid/payload/metadata/src/lib.rs
@@ -23,7 +23,9 @@
 use std::io::Read;
 use std::io::Write;
 
-pub use microdroid_metadata::metadata::{ApexPayload, ApkPayload, Metadata};
+pub use microdroid_metadata::metadata::{
+    ApexPayload, ApkPayload, Metadata, Metadata_oneof_payload as PayloadMetadata, PayloadConfig,
+};
 
 /// Reads a metadata from a reader
 pub fn read_metadata<T: Read>(mut r: T) -> Result<Metadata> {
diff --git a/microdroid/payload/mk_payload.cc b/microdroid/payload/mk_payload.cc
index 4dbcabf..d31333f 100644
--- a/microdroid/payload/mk_payload.cc
+++ b/microdroid/payload/mk_payload.cc
@@ -181,7 +181,7 @@
     }
 
     if (config.payload_config_path.has_value()) {
-        *metadata.mutable_payload_config_path() = config.payload_config_path.value();
+        *metadata.mutable_config_path() = config.payload_config_path.value();
     }
 
     std::ofstream out(filename);
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 30521f6..90cabb6 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -34,7 +34,7 @@
 use glob::glob;
 use itertools::sorted;
 use log::{error, info};
-use microdroid_metadata::{write_metadata, Metadata};
+use microdroid_metadata::{write_metadata, Metadata, PayloadMetadata};
 use microdroid_payload_config::{Task, TaskType, VmPayloadConfig};
 use openssl::sha::Sha512;
 use payload::{get_apex_data_from_payload, load_metadata, to_metadata};
@@ -301,9 +301,14 @@
         verified_data
     };
 
+    let payload_config_path = match metadata.payload {
+        Some(PayloadMetadata::config_path(p)) => p,
+        _ => bail!("Unsupported payload config"),
+    };
+
     // To minimize the exposure to untrusted data, derive dice profile as soon as possible.
     info!("DICE derivation for payload");
-    dice_derivation(&verified_data, &metadata.payload_config_path)?;
+    dice_derivation(&verified_data, &payload_config_path)?;
 
     // Before reading a file from the APK, start zipfuse
     let noexec = false;
@@ -316,11 +321,11 @@
     .context("Failed to run zipfuse")?;
 
     ensure!(
-        !metadata.payload_config_path.is_empty(),
+        !payload_config_path.is_empty(),
         MicrodroidError::InvalidConfig("No payload_config_path in metadata".to_string())
     );
 
-    let config = load_config(Path::new(&metadata.payload_config_path))?;
+    let config = load_config(Path::new(&payload_config_path))?;
 
     let task = config
         .task
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
index cf5398d..9b0a658 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
@@ -15,6 +15,8 @@
  */
 package android.system.virtualizationservice;
 
+import android.system.virtualizationservice.VirtualMachinePayloadConfig;
+
 /** Configuration for running an App in a VM */
 parcelable VirtualMachineAppConfig {
     /** Name of VM */
@@ -32,8 +34,20 @@
     /** instance.img that has per-instance data */
     ParcelFileDescriptor instanceImage;
 
-    /** Path to a configuration in an APK. This is the actual configuration for a VM. */
-    @utf8InCpp String configPath;
+    union Payload {
+        /**
+         * Path to a JSON file in an APK containing the configuration.
+         */
+        @utf8InCpp String configPath;
+
+        /**
+         * Configuration provided explicitly.
+         */
+        VirtualMachinePayloadConfig payloadConfig;
+    }
+
+    /** Detailed configuration for the VM, specifying how the payload will be run. */
+    Payload payload;
 
     enum DebugLevel {
         /** Not debuggable at all */
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachinePayloadConfig.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachinePayloadConfig.aidl
new file mode 100644
index 0000000..0c83349
--- /dev/null
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachinePayloadConfig.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2022 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.
+ */
+
+package android.system.virtualizationservice;
+
+parcelable VirtualMachinePayloadConfig {
+    /**
+     * Path to the payload executable code in an APK. The code is in the form of a .so with a
+     * defined entry point; inside the VM this file is loaded and the entry function invoked.
+     */
+    @utf8InCpp String payloadPath;
+
+    /**
+     * Whether to export tombstones (VM crash details) from the VM to the host.
+     */
+    boolean exportTombstones;
+
+    /**
+     * Command-line style arguments to be passed to the payload when it is executed.
+     * TODO(b/249064104): Remove this
+     */
+    @utf8InCpp String[] args;
+}
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index b35f8da..22418b9 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -29,9 +29,10 @@
     IVirtualizationService::IVirtualizationService,
     Partition::Partition,
     PartitionType::PartitionType,
-    VirtualMachineAppConfig::VirtualMachineAppConfig,
+    VirtualMachineAppConfig::{VirtualMachineAppConfig, Payload::Payload},
     VirtualMachineConfig::VirtualMachineConfig,
     VirtualMachineDebugInfo::VirtualMachineDebugInfo,
+    VirtualMachinePayloadConfig::VirtualMachinePayloadConfig,
     VirtualMachineRawConfig::VirtualMachineRawConfig,
     VirtualMachineState::VirtualMachineState,
 };
@@ -49,7 +50,7 @@
 use disk::QcowFile;
 use apkverify::{HashAlgorithm, V4Signature};
 use log::{debug, error, info, warn};
-use microdroid_payload_config::VmPayloadConfig;
+use microdroid_payload_config::{VmPayloadConfig, OsConfig, Task, TaskType};
 use rustutils::system_properties;
 use semver::VersionReq;
 use std::convert::TryInto;
@@ -85,6 +86,8 @@
 
 const CHUNK_RECV_MAX_LEN: usize = 1024;
 
+const MICRODROID_OS_NAME: &str = "microdroid";
+
 /// Implementation of `IVirtualizationService`, the entry point of the AIDL service.
 #[derive(Debug, Default)]
 pub struct VirtualizationService {
@@ -376,15 +379,10 @@
         let config = match config {
             VirtualMachineConfig::AppConfig(config) => BorrowedOrOwned::Owned(
                 load_app_config(config, &temporary_directory).map_err(|e| {
-                    error!("Failed to load app config from {}: {:?}", &config.configPath, e);
                     *is_protected = config.protectedVm;
-                    Status::new_service_specific_error_str(
-                        -1,
-                        Some(format!(
-                            "Failed to load app config from {}: {:?}",
-                            &config.configPath, e
-                        )),
-                    )
+                    let message = format!("Failed to load app config: {:?}", e);
+                    error!("{}", message);
+                    Status::new_service_specific_error_str(-1, Some(message))
                 })?,
             ),
             VirtualMachineConfig::RawConfig(config) => BorrowedOrOwned::Borrowed(config),
@@ -604,16 +602,18 @@
     let apk_file = clone_file(config.apk.as_ref().unwrap())?;
     let idsig_file = clone_file(config.idsig.as_ref().unwrap())?;
     let instance_file = clone_file(config.instanceImage.as_ref().unwrap())?;
-    let config_path = &config.configPath;
 
-    let mut apk_zip = ZipArchive::new(&apk_file)?;
-    let config_file = apk_zip.by_name(config_path)?;
-    let vm_payload_config: VmPayloadConfig = serde_json::from_reader(config_file)?;
+    let vm_payload_config = match &config.payload {
+        Payload::ConfigPath(config_path) => {
+            load_vm_payload_config_from_file(&apk_file, config_path.as_str())
+                .with_context(|| format!("Couldn't read config from {}", config_path))?
+        }
+        Payload::PayloadConfig(payload_config) => create_vm_payload_config(payload_config),
+    };
 
-    let os_name = &vm_payload_config.os.name;
-
-    // For now, the only supported "os" value is "microdroid"
-    if os_name != "microdroid" {
+    // For now, the only supported OS is Microdroid
+    let os_name = vm_payload_config.os.name.as_str();
+    if os_name != MICRODROID_OS_NAME {
         bail!("Unknown OS \"{}\"", os_name);
     }
 
@@ -633,21 +633,45 @@
     vm_config.taskProfiles = config.taskProfiles.clone();
 
     // Microdroid requires an additional init ramdisk & payload disk image
-    if os_name == "microdroid" {
-        add_microdroid_images(
-            config,
-            temporary_directory,
-            apk_file,
-            idsig_file,
-            instance_file,
-            &vm_payload_config,
-            &mut vm_config,
-        )?;
-    }
+    add_microdroid_images(
+        config,
+        temporary_directory,
+        apk_file,
+        idsig_file,
+        instance_file,
+        &vm_payload_config,
+        &mut vm_config,
+    )?;
 
     Ok(vm_config)
 }
 
+fn load_vm_payload_config_from_file(apk_file: &File, config_path: &str) -> Result<VmPayloadConfig> {
+    let mut apk_zip = ZipArchive::new(apk_file)?;
+    let config_file = apk_zip.by_name(config_path)?;
+    Ok(serde_json::from_reader(config_file)?)
+}
+
+fn create_vm_payload_config(payload_config: &VirtualMachinePayloadConfig) -> VmPayloadConfig {
+    // There isn't an actual config file. Construct a synthetic VmPayloadConfig from the explicit
+    // parameters we've been given. Microdroid will do something equivalent inside the VM using the
+    // payload config that we send it via the metadata file.
+    let task = Task {
+        type_: TaskType::MicrodroidLauncher,
+        command: payload_config.payloadPath.clone(),
+        args: payload_config.args.clone(),
+    };
+    VmPayloadConfig {
+        os: OsConfig { name: MICRODROID_OS_NAME.to_owned() },
+        task: Some(task),
+        apexes: vec![],
+        extra_apks: vec![],
+        prefer_staged: false,
+        export_tombstones: payload_config.exportTombstones,
+        enable_authfs: false,
+    }
+}
+
 /// Generates a unique filename to use for a composite disk image.
 fn make_composite_image_filenames(
     temporary_directory: &Path,
diff --git a/virtualizationservice/src/atom.rs b/virtualizationservice/src/atom.rs
index 3b29d19..eabb4cc 100644
--- a/virtualizationservice/src/atom.rs
+++ b/virtualizationservice/src/atom.rs
@@ -16,23 +16,47 @@
 
 use crate::aidl::clone_file;
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
-    DeathReason::DeathReason, IVirtualMachine::IVirtualMachine,
-    VirtualMachineAppConfig::VirtualMachineAppConfig, VirtualMachineConfig::VirtualMachineConfig,
+    DeathReason::DeathReason,
+    IVirtualMachine::IVirtualMachine,
+    VirtualMachineAppConfig::{Payload::Payload, VirtualMachineAppConfig},
+    VirtualMachineConfig::VirtualMachineConfig,
 };
 use android_system_virtualizationservice::binder::{Status, Strong};
 use anyhow::{anyhow, Result};
-use binder::ThreadState;
+use binder::{ParcelFileDescriptor, ThreadState};
 use log::{trace, warn};
 use microdroid_payload_config::VmPayloadConfig;
 use statslog_virtualization_rust::{vm_booted, vm_creation_requested, vm_exited};
 use std::time::{Duration, SystemTime};
 use zip::ZipArchive;
 
-fn get_vm_payload_config(config: &VirtualMachineAppConfig) -> Result<VmPayloadConfig> {
-    let apk = config.apk.as_ref().ok_or_else(|| anyhow!("APK is none"))?;
+fn get_apex_list(config: &VirtualMachineAppConfig) -> String {
+    match &config.payload {
+        Payload::PayloadConfig(_) => String::new(),
+        Payload::ConfigPath(config_path) => {
+            let vm_payload_config = get_vm_payload_config(&config.apk, config_path);
+            if let Ok(vm_payload_config) = vm_payload_config {
+                vm_payload_config
+                    .apexes
+                    .iter()
+                    .map(|x| x.name.clone())
+                    .collect::<Vec<String>>()
+                    .join(":")
+            } else {
+                "INFO: Can't get VmPayloadConfig".to_owned()
+            }
+        }
+    }
+}
+
+fn get_vm_payload_config(
+    apk_fd: &Option<ParcelFileDescriptor>,
+    config_path: &str,
+) -> Result<VmPayloadConfig> {
+    let apk = apk_fd.as_ref().ok_or_else(|| anyhow!("APK is none"))?;
     let apk_file = clone_file(apk)?;
     let mut apk_zip = ZipArchive::new(&apk_file)?;
-    let config_file = apk_zip.by_name(&config.configPath)?;
+    let config_file = apk_zip.by_name(config_path)?;
     let vm_payload_config: VmPayloadConfig = serde_json::from_reader(config_file)?;
     Ok(vm_payload_config)
 }
@@ -63,38 +87,22 @@
         }
     }
 
-    let vm_identifier;
-    let config_type;
-    let num_cpus;
-    let memory_mib;
-    let apexes;
-    match config {
-        VirtualMachineConfig::AppConfig(config) => {
-            vm_identifier = &config.name;
-            config_type = vm_creation_requested::ConfigType::VirtualMachineAppConfig;
-            num_cpus = config.numCpus;
-            memory_mib = config.memoryMib;
-
-            let vm_payload_config = get_vm_payload_config(config);
-            if let Ok(vm_payload_config) = vm_payload_config {
-                apexes = vm_payload_config
-                    .apexes
-                    .iter()
-                    .map(|x| x.name.clone())
-                    .collect::<Vec<String>>()
-                    .join(":");
-            } else {
-                apexes = "INFO: Can't get VmPayloadConfig".into();
-            }
-        }
-        VirtualMachineConfig::RawConfig(config) => {
-            vm_identifier = &config.name;
-            config_type = vm_creation_requested::ConfigType::VirtualMachineRawConfig;
-            num_cpus = config.numCpus;
-            memory_mib = config.memoryMib;
-            apexes = String::new();
-        }
-    }
+    let (vm_identifier, config_type, num_cpus, memory_mib, apexes) = match config {
+        VirtualMachineConfig::AppConfig(config) => (
+            &config.name,
+            vm_creation_requested::ConfigType::VirtualMachineAppConfig,
+            config.numCpus,
+            config.memoryMib,
+            get_apex_list(config),
+        ),
+        VirtualMachineConfig::RawConfig(config) => (
+            &config.name,
+            vm_creation_requested::ConfigType::VirtualMachineRawConfig,
+            config.numCpus,
+            config.memoryMib,
+            String::new(),
+        ),
+    };
 
     let vm_creation_requested = vm_creation_requested::VmCreationRequested {
         uid: ThreadState::get_calling_uid() as i32,
diff --git a/virtualizationservice/src/payload.rs b/virtualizationservice/src/payload.rs
index 06b9716..3efd7ac 100644
--- a/virtualizationservice/src/payload.rs
+++ b/virtualizationservice/src/payload.rs
@@ -15,14 +15,16 @@
 //! Payload disk image
 
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
-    DiskImage::DiskImage, Partition::Partition, VirtualMachineAppConfig::DebugLevel::DebugLevel,
-    VirtualMachineAppConfig::VirtualMachineAppConfig,
+    DiskImage::DiskImage,
+    Partition::Partition,
+    VirtualMachineAppConfig::DebugLevel::DebugLevel,
+    VirtualMachineAppConfig::{Payload::Payload, VirtualMachineAppConfig},
     VirtualMachineRawConfig::VirtualMachineRawConfig,
 };
 use anyhow::{anyhow, bail, Context, Result};
 use binder::{wait_for_interface, ParcelFileDescriptor};
 use log::{info, warn};
-use microdroid_metadata::{ApexPayload, ApkPayload, Metadata};
+use microdroid_metadata::{ApexPayload, ApkPayload, Metadata, PayloadConfig, PayloadMetadata};
 use microdroid_payload_config::{ApexConfig, VmPayloadConfig};
 use once_cell::sync::OnceCell;
 use packagemanager_aidl::aidl::android::content::pm::IPackageManagerNative::IPackageManagerNative;
@@ -156,11 +158,22 @@
 }
 
 fn make_metadata_file(
-    config_path: &str,
+    app_config: &VirtualMachineAppConfig,
     apex_infos: &[&ApexInfo],
     temporary_directory: &Path,
 ) -> Result<ParcelFileDescriptor> {
-    let metadata_path = temporary_directory.join("metadata");
+    let payload_metadata = match &app_config.payload {
+        Payload::PayloadConfig(payload_config) => PayloadMetadata::config(PayloadConfig {
+            payload_binary_path: payload_config.payloadPath.clone(),
+            export_tombstones: payload_config.exportTombstones,
+            args: payload_config.args.clone().into(),
+            ..Default::default()
+        }),
+        Payload::ConfigPath(config_path) => {
+            PayloadMetadata::config_path(format!("/mnt/apk/{}", config_path))
+        }
+    };
+
     let metadata = Metadata {
         version: 1,
         apexes: apex_infos
@@ -183,11 +196,12 @@
             ..Default::default()
         })
         .into(),
-        payload_config_path: format!("/mnt/apk/{}", config_path),
+        payload: Some(payload_metadata),
         ..Default::default()
     };
 
     // Write metadata to file.
+    let metadata_path = temporary_directory.join("metadata");
     let mut metadata_file = OpenOptions::new()
         .create_new(true)
         .read(true)
@@ -235,8 +249,7 @@
         collect_apex_infos(&apex_list, &vm_payload_config.apexes, app_config.debugLevel);
     info!("Microdroid payload APEXes: {:?}", apex_infos.iter().map(|ai| &ai.name));
 
-    let metadata_file =
-        make_metadata_file(&app_config.configPath, &apex_infos, temporary_directory)?;
+    let metadata_file = make_metadata_file(app_config, &apex_infos, temporary_directory)?;
     // put metadata at the first partition
     let mut partitions = vec![Partition {
         label: "payload-metadata".to_owned(),
diff --git a/vm/src/main.rs b/vm/src/main.rs
index 0845897..21cc74b 100644
--- a/vm/src/main.rs
+++ b/vm/src/main.rs
@@ -48,7 +48,7 @@
         instance: PathBuf,
 
         /// Path to VM config JSON within APK (e.g. assets/vm_config.json)
-        config_path: String,
+        config_path: Option<String>,
 
         /// Name of VM
         #[clap(long)]
@@ -205,7 +205,7 @@
             &apk,
             &idsig,
             &instance,
-            &config_path,
+            config_path.as_deref().unwrap_or(""),
             daemonize,
             console.as_deref(),
             log.as_deref(),
diff --git a/vm/src/run.rs b/vm/src/run.rs
index 44e15f9..c524c59 100644
--- a/vm/src/run.rs
+++ b/vm/src/run.rs
@@ -16,9 +16,10 @@
 
 use crate::create_partition::command_create_partition;
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
-    IVirtualizationService::IVirtualizationService, PartitionType::PartitionType,
-    VirtualMachineAppConfig::DebugLevel::DebugLevel,
-    VirtualMachineAppConfig::VirtualMachineAppConfig, VirtualMachineConfig::VirtualMachineConfig,
+    IVirtualizationService::IVirtualizationService,
+    PartitionType::PartitionType,
+    VirtualMachineAppConfig::{DebugLevel::DebugLevel, Payload::Payload, VirtualMachineAppConfig},
+    VirtualMachineConfig::VirtualMachineConfig,
     VirtualMachineState::VirtualMachineState,
 };
 use anyhow::{bail, Context, Error};
@@ -96,7 +97,7 @@
         idsig: idsig_fd.into(),
         extraIdsigs: extra_idsig_fds,
         instanceImage: open_parcel_file(instance, true /* writable */)?.into(),
-        configPath: config_path.to_owned(),
+        payload: Payload::ConfigPath(config_path.to_owned()),
         debugLevel: debug_level,
         protectedVm: protected,
         memoryMib: mem.unwrap_or(0) as i32, // 0 means use the VM default