Handle PayloadConfig in Microdroid

Either read the config from JSON or build it from the values in
metadata.

In the latter case, include a hash of the config values in the DICE
config_desc instead of the config path.

Bug: 243513572
Test: atest MicrodroidTests
Change-Id: Ifa1c5dfa17d11a1589621fa265709735d73d4f61
diff --git a/microdroid/payload/metadata.proto b/microdroid/payload/metadata.proto
index 229d03f..06cbbf4 100644
--- a/microdroid/payload/metadata.proto
+++ b/microdroid/payload/metadata.proto
@@ -68,12 +68,8 @@
   // 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;
+  repeated string args = 2;
 }
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 90cabb6..b4b2c8b 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -30,12 +30,12 @@
 use anyhow::{anyhow, bail, ensure, Context, Error, Result};
 use apkverify::{get_public_key_der, verify, V4Signature};
 use binder::{wait_for_interface, Strong};
-use diced_utils::cbor::encode_header;
+use diced_utils::cbor::{encode_header, encode_number};
 use glob::glob;
 use itertools::sorted;
 use log::{error, info};
 use microdroid_metadata::{write_metadata, Metadata, PayloadMetadata};
-use microdroid_payload_config::{Task, TaskType, VmPayloadConfig};
+use microdroid_payload_config::{Task, TaskType, VmPayloadConfig, OsConfig};
 use openssl::sha::Sha512;
 use payload::{get_apex_data_from_payload, load_metadata, to_metadata};
 use rand::Fill;
@@ -191,7 +191,10 @@
     }
 }
 
-fn dice_derivation(verified_data: &MicrodroidData, payload_config_path: &str) -> Result<()> {
+fn dice_derivation(
+    verified_data: &MicrodroidData,
+    payload_metadata: &PayloadMetadata,
+) -> Result<()> {
     // Calculate compound digests of code and authorities
     let mut code_hash_ctx = Sha512::new();
     let mut authority_hash_ctx = Sha512::new();
@@ -210,15 +213,33 @@
 
     // {
     //   -70002: "Microdroid payload",
-    //   -71000: payload_config_path
+    //   ? -71000: tstr // payload_config_path
+    //   ? -71001: PayloadConfig
     // }
+    // PayloadConfig = {
+    //   1: tstr // payload_binary_path
+    //   // TODO(b/249064104 Either include args, or deprecate them
+    // }
+
     let mut config_desc = vec![
-        0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72, 0x6f,
-        0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01, 0x15, 0x57,
+        0xa2, // map(2)
+        0x3a, 0x00, 0x01, 0x11, 0x71, // -70002
+        0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79,
+        0x6c, 0x6f, 0x61, 0x64, // "Microdroid payload"
     ];
-    let config_path_bytes = payload_config_path.as_bytes();
-    encode_header(3, config_path_bytes.len().try_into().unwrap(), &mut config_desc)?;
-    config_desc.extend_from_slice(config_path_bytes);
+
+    match payload_metadata {
+        PayloadMetadata::config_path(payload_config_path) => {
+            encode_negative_number(-71000, &mut config_desc)?;
+            encode_tstr(payload_config_path, &mut config_desc)?;
+        }
+        PayloadMetadata::config(payload_config) => {
+            encode_negative_number(-71001, &mut config_desc)?;
+            encode_header(5, 1, &mut config_desc)?; // map(1)
+            encode_number(1, &mut config_desc)?;
+            encode_tstr(&payload_config.payload_binary_path, &mut config_desc)?;
+        }
+    }
 
     // Check app debuggability, conervatively assuming it is debuggable
     let app_debuggable = system_properties::read_bool(APP_DEBUGGABLE_PROP, true)?;
@@ -240,6 +261,19 @@
     Ok(())
 }
 
+fn encode_tstr(tstr: &str, buffer: &mut Vec<u8>) -> Result<()> {
+    let bytes = tstr.as_bytes();
+    encode_header(3, bytes.len().try_into().unwrap(), buffer)?;
+    buffer.extend_from_slice(bytes);
+    Ok(())
+}
+
+fn encode_negative_number(n: i64, buffer: &mut dyn Write) -> Result<()> {
+    ensure!(n < 0);
+    let n = -1 - n;
+    encode_header(1, n.try_into().unwrap(), buffer)
+}
+
 fn is_strict_boot() -> bool {
     Path::new(AVF_STRICT_BOOT).exists()
 }
@@ -301,14 +335,13 @@
         verified_data
     };
 
-    let payload_config_path = match metadata.payload {
-        Some(PayloadMetadata::config_path(p)) => p,
-        _ => bail!("Unsupported payload config"),
-    };
+    let payload_metadata = metadata.payload.ok_or_else(|| {
+        MicrodroidError::InvalidConfig("No payload config in metadata".to_string())
+    })?;
 
     // To minimize the exposure to untrusted data, derive dice profile as soon as possible.
     info!("DICE derivation for payload");
-    dice_derivation(&verified_data, &payload_config_path)?;
+    dice_derivation(&verified_data, &payload_metadata)?;
 
     // Before reading a file from the APK, start zipfuse
     let noexec = false;
@@ -320,12 +353,7 @@
     )
     .context("Failed to run zipfuse")?;
 
-    ensure!(
-        !payload_config_path.is_empty(),
-        MicrodroidError::InvalidConfig("No payload_config_path in metadata".to_string())
-    );
-
-    let config = load_config(Path::new(&payload_config_path))?;
+    let config = load_config(payload_metadata)?;
 
     let task = config
         .task
@@ -334,7 +362,7 @@
 
     if config.extra_apks.len() != verified_data.extra_apks_data.len() {
         return Err(anyhow!(
-            "config expects {} extra apks, but found only {}",
+            "config expects {} extra apks, but found {}",
             config.extra_apks.len(),
             verified_data.extra_apks_data.len()
         ));
@@ -620,10 +648,31 @@
     }
 }
 
-fn load_config(path: &Path) -> Result<VmPayloadConfig> {
-    info!("loading config from {:?}...", path);
-    let file = ioutil::wait_for_file(path, WAIT_TIMEOUT)?;
-    Ok(serde_json::from_reader(file)?)
+fn load_config(payload_metadata: PayloadMetadata) -> Result<VmPayloadConfig> {
+    match payload_metadata {
+        PayloadMetadata::config_path(path) => {
+            let path = Path::new(&path);
+            info!("loading config from {:?}...", path);
+            let file = ioutil::wait_for_file(path, WAIT_TIMEOUT)?;
+            Ok(serde_json::from_reader(file)?)
+        }
+        PayloadMetadata::config(payload_config) => {
+            let task = Task {
+                type_: TaskType::MicrodroidLauncher,
+                command: payload_config.payload_binary_path,
+                args: payload_config.args.into_vec(),
+            };
+            Ok(VmPayloadConfig {
+                os: OsConfig { name: "microdroid".to_owned() },
+                task: Some(task),
+                apexes: vec![],
+                extra_apks: vec![],
+                prefer_staged: false,
+                export_tombstones: false,
+                enable_authfs: false,
+            })
+        }
+    }
 }
 
 /// Loads the crashkernel into memory using kexec if the VM is loaded with `crashkernel=' parameter
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachinePayloadConfig.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachinePayloadConfig.aidl
index 0c83349..4d37848 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachinePayloadConfig.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachinePayloadConfig.aidl
@@ -24,11 +24,6 @@
     @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
      */
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 22418b9..563fab0 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -667,7 +667,7 @@
         apexes: vec![],
         extra_apks: vec![],
         prefer_staged: false,
-        export_tombstones: payload_config.exportTombstones,
+        export_tombstones: false,
         enable_authfs: false,
     }
 }
diff --git a/virtualizationservice/src/payload.rs b/virtualizationservice/src/payload.rs
index 3efd7ac..82aa760 100644
--- a/virtualizationservice/src/payload.rs
+++ b/virtualizationservice/src/payload.rs
@@ -165,7 +165,6 @@
     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()
         }),