Merge "Add memory size to VM config."
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
index 9e1dee2..612c498 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
@@ -42,4 +42,7 @@
 
     /** Whether the VM should be a protected VM. */
     boolean protected_vm;
+
+    /** The amount of RAM to give the VM, in MiB. 0 or negative to use the default. */
+    int memory_mib;
 }
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index bc1761b..bc19109 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -41,6 +41,7 @@
 use std::convert::TryInto;
 use std::ffi::CString;
 use std::fs::{File, create_dir};
+use std::num::NonZeroU32;
 use std::os::unix::io::AsRawFd;
 use std::path::{Path, PathBuf};
 use std::sync::{Arc, Mutex, Weak};
@@ -144,6 +145,7 @@
             disks,
             params: config.params.to_owned(),
             protected: config.protected_vm,
+            memory_mib: config.memory_mib.try_into().ok().and_then(NonZeroU32::new),
         };
         let composite_disk_fds: Vec<_> =
             indirect_files.iter().map(|file| file.as_raw_fd()).collect();
diff --git a/virtualizationservice/src/crosvm.rs b/virtualizationservice/src/crosvm.rs
index ae8388a..5873cd9 100644
--- a/virtualizationservice/src/crosvm.rs
+++ b/virtualizationservice/src/crosvm.rs
@@ -21,6 +21,7 @@
 use log::{debug, error, info};
 use shared_child::SharedChild;
 use std::fs::{remove_dir_all, File};
+use std::num::NonZeroU32;
 use std::os::unix::io::{AsRawFd, RawFd};
 use std::path::PathBuf;
 use std::process::Command;
@@ -40,6 +41,7 @@
     pub disks: Vec<DiskFile>,
     pub params: Option<String>,
     pub protected: bool,
+    pub memory_mib: Option<NonZeroU32>,
 }
 
 /// A disk image to pass to crosvm for a VM.
@@ -173,6 +175,10 @@
         command.arg("--protected-vm");
     }
 
+    if let Some(memory_mib) = config.memory_mib {
+        command.arg("--mem").arg(memory_mib.to_string());
+    }
+
     if let Some(log_fd) = log_fd {
         command.stdout(log_fd);
     } else {
diff --git a/vmconfig/src/lib.rs b/vmconfig/src/lib.rs
index 7b0d2a5..1a16d30 100644
--- a/vmconfig/src/lib.rs
+++ b/vmconfig/src/lib.rs
@@ -23,8 +23,10 @@
 
 use anyhow::{bail, Context, Error, Result};
 use serde::{Deserialize, Serialize};
+use std::convert::TryInto;
 use std::fs::{File, OpenOptions};
 use std::io::BufReader;
+use std::num::NonZeroU32;
 use std::path::{Path, PathBuf};
 
 /// Configuration for a particular VM to be started.
@@ -46,6 +48,9 @@
     /// Whether the VM should be a protected VM.
     #[serde(default)]
     pub protected: bool,
+    /// The amount of RAM to give the VM, in MiB.
+    #[serde(default)]
+    pub memory_mib: Option<NonZeroU32>,
 }
 
 impl VmConfig {
@@ -77,6 +82,11 @@
     /// Convert the `VmConfig` to a [`VirtualMachineConfig`] which can be passed to the Virt
     /// Manager.
     pub fn to_parcelable(&self) -> Result<VirtualMachineRawConfig, Error> {
+        let memory_mib = if let Some(memory_mib) = self.memory_mib {
+            memory_mib.get().try_into().context("Invalid memory_mib")?
+        } else {
+            0
+        };
         Ok(VirtualMachineRawConfig {
             kernel: maybe_open_parcel_file(&self.kernel, false)?,
             initrd: maybe_open_parcel_file(&self.initrd, false)?,
@@ -84,6 +94,7 @@
             bootloader: maybe_open_parcel_file(&self.bootloader, false)?,
             disks: self.disks.iter().map(DiskImage::to_parcelable).collect::<Result<_, Error>>()?,
             protected_vm: self.protected,
+            memory_mib,
         })
     }
 }