Support payload path for vm run-app

Bug: 258323168
Test: atest MicrodroidTests MicrodroidHostTestCases
Test: manually run VM with --config-path and --payload-path
Change-Id: I137c8b8efc33b49cb22efaba0e5917dd469c2462
diff --git a/docs/getting_started/index.md b/docs/getting_started/index.md
index 245aba6..5f552f9 100644
--- a/docs/getting_started/index.md
+++ b/docs/getting_started/index.md
@@ -133,7 +133,8 @@
   --debug full \
   /data/local/tmp/virt/MicrodroidDemoApp.apk \
   /data/local/tmp/virt/MicrodroidDemoApp.apk.idsig \
-  /data/local/tmp/virt/instance.img assets/vm_config.json
+  /data/local/tmp/virt/instance.img \
+  --payload-path MicrodroidTestNativeLib.so
 ```
 
 ## Building and updating CrosVM and VirtualizationService {#building-and-updating}
diff --git a/microdroid/README.md b/microdroid/README.md
index 2519416..41278a5 100644
--- a/microdroid/README.md
+++ b/microdroid/README.md
@@ -141,7 +141,7 @@
 PATH_TO_YOUR_APP \
 $TEST_ROOT/MyApp.apk.idsig \
 $TEST_ROOT/instance.img \
-assets/VM_CONFIG_FILE
+--config-path assets/VM_CONFIG_FILE
 ```
 
 The last command lets you know the CID assigned to the VM. The console output
diff --git a/vm/src/main.rs b/vm/src/main.rs
index 3b887d3..89d56d4 100644
--- a/vm/src/main.rs
+++ b/vm/src/main.rs
@@ -48,8 +48,13 @@
         instance: PathBuf,
 
         /// Path to VM config JSON within APK (e.g. assets/vm_config.json)
+        #[clap(long)]
         config_path: Option<String>,
 
+        /// Path to VM payload binary within APK (e.g. MicrodroidTestNativeLib.so)
+        #[clap(long)]
+        payload_path: Option<String>,
+
         /// Name of VM
         #[clap(long)]
         name: Option<String>,
@@ -201,6 +206,7 @@
             storage,
             storage_size,
             config_path,
+            payload_path,
             daemonize,
             console,
             log,
@@ -219,7 +225,8 @@
             &instance,
             storage.as_deref(),
             storage_size,
-            config_path.as_deref().unwrap_or(""),
+            config_path,
+            payload_path,
             daemonize,
             console.as_deref(),
             log.as_deref(),
diff --git a/vm/src/run.rs b/vm/src/run.rs
index de8f1c0..53402da 100644
--- a/vm/src/run.rs
+++ b/vm/src/run.rs
@@ -20,6 +20,7 @@
     PartitionType::PartitionType,
     VirtualMachineAppConfig::{DebugLevel::DebugLevel, Payload::Payload, VirtualMachineAppConfig},
     VirtualMachineConfig::VirtualMachineConfig,
+    VirtualMachinePayloadConfig::VirtualMachinePayloadConfig,
     VirtualMachineState::VirtualMachineState,
 };
 use anyhow::{bail, Context, Error};
@@ -43,7 +44,8 @@
     instance: &Path,
     storage: Option<&Path>,
     storage_size: Option<u64>,
-    config_path: &str,
+    config_path: Option<String>,
+    payload_path: Option<String>,
     daemonize: bool,
     console_path: Option<&Path>,
     log_path: Option<&Path>,
@@ -57,7 +59,11 @@
 ) -> Result<(), Error> {
     let apk_file = File::open(apk).context("Failed to open APK file")?;
 
-    let extra_apks = parse_extra_apk_list(apk, config_path)?;
+    let extra_apks = match config_path.as_deref() {
+        Some(path) => parse_extra_apk_list(apk, path)?,
+        None => vec![],
+    };
+
     if extra_apks.len() != extra_idsigs.len() {
         bail!(
             "Found {} extra apks, but there are {} extra idsigs",
@@ -108,6 +114,19 @@
     let extra_idsig_files: Result<Vec<File>, _> = extra_idsigs.iter().map(File::open).collect();
     let extra_idsig_fds = extra_idsig_files?.into_iter().map(ParcelFileDescriptor::new).collect();
 
+    let payload = if let Some(config_path) = config_path {
+        if payload_path.is_some() {
+            bail!("Only one of --config-path or --payload-path can be defined")
+        }
+        Payload::ConfigPath(config_path)
+    } else if let Some(payload_path) = payload_path {
+        Payload::PayloadConfig(VirtualMachinePayloadConfig { payloadPath: payload_path })
+    } else {
+        bail!("Either --config-path or --payload-path must be defined")
+    };
+
+    let payload_config_str = format!("{:?}!{:?}", apk, payload);
+
     let config = VirtualMachineConfig::AppConfig(VirtualMachineAppConfig {
         name: name.unwrap_or_else(|| String::from("VmRunApp")),
         apk: apk_fd.into(),
@@ -115,22 +134,14 @@
         extraIdsigs: extra_idsig_fds,
         instanceImage: open_parcel_file(instance, true /* writable */)?.into(),
         encryptedStorageImage: storage,
-        payload: Payload::ConfigPath(config_path.to_owned()),
+        payload,
         debugLevel: debug_level,
         protectedVm: protected,
         memoryMib: mem.unwrap_or(0) as i32, // 0 means use the VM default
         numCpus: cpus.unwrap_or(1) as i32,
         taskProfiles: task_profiles,
     });
-    run(
-        service,
-        &config,
-        &format!("{:?}!{:?}", apk, config_path),
-        daemonize,
-        console_path,
-        log_path,
-        ramdump_path,
-    )
+    run(service, &config, &payload_config_str, daemonize, console_path, log_path, ramdump_path)
 }
 
 /// Run a VM from the given configuration file.
@@ -187,7 +198,7 @@
 fn run(
     service: &dyn IVirtualizationService,
     config: &VirtualMachineConfig,
-    config_path: &str,
+    payload_config: &str,
     daemonize: bool,
     console_path: Option<&Path>,
     log_path: Option<&Path>,
@@ -221,7 +232,7 @@
 
     println!(
         "Created VM from {} with CID {}, state is {}.",
-        config_path,
+        payload_config,
         vm.cid(),
         state_to_str(vm.state()?)
     );