Merge changes I065f5c5d,I57656492

* changes:
  microdroid_manager executes a task via microdroid_launcher
  Schema for the VM payload config
diff --git a/compositediskconfig/Android.bp b/compositediskconfig/Android.bp
new file mode 100644
index 0000000..4608323
--- /dev/null
+++ b/compositediskconfig/Android.bp
@@ -0,0 +1,18 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_library {
+    name: "libcompositediskconfig",
+    host_supported: true,
+    crate_name: "compositediskconfig",
+    srcs: ["src/lib.rs"],
+    edition: "2018",
+    rustlibs: [
+        "libserde_json",
+        "libserde",
+    ],
+    apex_available: [
+        "com.android.virt",
+    ],
+}
diff --git a/virtualizationservice/src/composite/config.rs b/compositediskconfig/src/lib.rs
similarity index 78%
rename from virtualizationservice/src/composite/config.rs
rename to compositediskconfig/src/lib.rs
index 1a915ba..3546dd3 100644
--- a/virtualizationservice/src/composite/config.rs
+++ b/compositediskconfig/src/lib.rs
@@ -12,13 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-//! JSON configuration for running `mk_cdisk`.
+//! JSON configuration for composite disks, as used for running `mk_cdisk` and by the `vm` tool.
 
-use anyhow::{Context, Error};
 use serde::{Deserialize, Serialize};
 use std::io::Write;
 use std::path::PathBuf;
 
+/// Configuration for running `mk_cdisk`.
 #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
 pub struct Config {
     /// The set of partitions to be assembled into a composite image.
@@ -38,7 +38,8 @@
 }
 
 impl Config {
-    pub fn write_json(&self, writer: impl Write) -> Result<(), Error> {
-        serde_json::to_writer(writer, self).context("Failed to write config JSON for mk_cdisk")
+    /// Write the configuration as JSON, in the format used by `mk_cdisk`.
+    pub fn write_json(&self, writer: impl Write) -> serde_json::Result<()> {
+        serde_json::to_writer(writer, self)
     }
 }
diff --git a/virtualizationservice/Android.bp b/virtualizationservice/Android.bp
index 2d78018..bad7f46 100644
--- a/virtualizationservice/Android.bp
+++ b/virtualizationservice/Android.bp
@@ -13,6 +13,7 @@
         "libandroid_logger",
         "libanyhow",
         "libcommand_fds",
+        "libcompositediskconfig",
         "liblog_rust",
         "libserde_json",
         "libserde",
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
index 7974e71..311c2e0 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
@@ -27,6 +27,9 @@
     IVirtualMachine startVm(
             in VirtualMachineConfig config, in @nullable ParcelFileDescriptor logFd);
 
+    /** Initialise an empty partition image of the given size to be used as a writable partition. */
+    void initializeWritablePartition(in ParcelFileDescriptor imageFd, long size);
+
     /**
      * Get a list of all currently running VMs. This method is only intended for debug purposes,
      * and as such is only permitted from the shell user.
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index c295388..7b63917 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -30,7 +30,9 @@
 };
 use command_fds::FdMapping;
 use log::{debug, error, warn};
+use std::convert::TryInto;
 use std::fs::{File, create_dir};
+use std::io::{Seek, SeekFrom, Write};
 use std::os::unix::io::AsRawFd;
 use std::path::{Path, PathBuf};
 use std::sync::{Arc, Mutex, Weak};
@@ -131,6 +133,36 @@
         Ok(VirtualMachine::create(instance))
     }
 
+    /// Initialise an empty partition image of the given size to be used as a writable partition.
+    fn initializeWritablePartition(
+        &self,
+        image_fd: &ParcelFileDescriptor,
+        size: i64,
+    ) -> binder::Result<()> {
+        let size: u64 = size.try_into().map_err(|e| {
+            error!("Invalid size {}: {}", size, e);
+            StatusCode::BAD_VALUE
+        })?;
+        let mut image = clone_file(image_fd)?;
+
+        // TODO: create a QCOW2 image instead, like `crosvm create_qcow2`, once `mk_cdisk` supports
+        // it (b/189211641).
+        if size > 0 {
+            // Extend the file to the given size by seeking to the size we want and writing a single
+            // 0 byte there.
+            image.seek(SeekFrom::Start(size - 1)).map_err(|e| {
+                error!("Failed to seek to desired size of image file ({}): {}.", size, e);
+                StatusCode::UNKNOWN_ERROR
+            })?;
+            image.write_all(&[0]).map_err(|e| {
+                error!("Failed to write 0 to image file: {}.", e);
+                StatusCode::UNKNOWN_ERROR
+            })?;
+        }
+
+        Ok(())
+    }
+
     /// Get a list of all currently running VMs. This method is only intended for debug purposes,
     /// and as such is only permitted from the shell user.
     fn debugListVms(&self) -> binder::Result<Vec<VirtualMachineDebugInfo>> {
diff --git a/virtualizationservice/src/composite.rs b/virtualizationservice/src/composite.rs
index eb738a7..37428eb 100644
--- a/virtualizationservice/src/composite.rs
+++ b/virtualizationservice/src/composite.rs
@@ -14,12 +14,10 @@
 
 //! Functions for running `mk_cdisk`.
 
-mod config;
-
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::Partition::Partition as AidlPartition;
 use anyhow::{bail, Context, Error};
 use command_fds::{CommandFdExt, FdMapping};
-use config::{Config, Partition};
+use compositediskconfig::{Config, Partition};
 use log::info;
 use std::fs::File;
 use std::os::unix::io::AsRawFd;
@@ -58,7 +56,9 @@
 
     // Write config to stdin of mk_cdisk on a separate thread to avoid deadlock, as it may not read
     // all of stdin before it blocks on writing to stdout.
-    let writer_thread = thread::spawn(move || config_json.write_json(&stdin));
+    let writer_thread = thread::spawn(move || {
+        config_json.write_json(&stdin).context("Failed to write config JSON for mk_cdisk")
+    });
     info!("Running {:?}", command);
     let output = child.wait_with_output()?;
     match writer_thread.join() {
diff --git a/vm/Android.bp b/vm/Android.bp
index e7148ca..c07beb2 100644
--- a/vm/Android.bp
+++ b/vm/Android.bp
@@ -10,6 +10,7 @@
     rustlibs: [
         "android.system.virtualizationservice-rust",
         "libanyhow",
+        "libcompositediskconfig",
         "libenv_logger",
         "liblibc",
         "liblog_rust",
diff --git a/vm/src/config.rs b/vm/src/config.rs
index 3bd023f..169fdab 100644
--- a/vm/src/config.rs
+++ b/vm/src/config.rs
@@ -21,6 +21,7 @@
     binder::ParcelFileDescriptor,
 };
 use anyhow::{bail, Context, Error};
+use compositediskconfig::Partition;
 use serde::{Deserialize, Serialize};
 use std::fs::{File, OpenOptions};
 use std::io::BufReader;
@@ -100,7 +101,7 @@
 impl DiskImage {
     fn to_parcelable(&self) -> Result<AidlDiskImage, Error> {
         let partitions =
-            self.partitions.iter().map(Partition::to_parcelable).collect::<Result<_, Error>>()?;
+            self.partitions.iter().map(partition_to_parcelable).collect::<Result<_, Error>>()?;
         Ok(AidlDiskImage {
             image: maybe_open_parcel_file(&self.image, self.writable)?,
             writable: self.writable,
@@ -109,27 +110,12 @@
     }
 }
 
-// TODO: Share this type with virtualizationservice::composite::config.
-/// A partition for a disk image to be made available to the VM.
-#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
-pub struct Partition {
-    /// A label for the partition.
-    pub label: String,
-    /// The filename of the partition image.
-    pub path: PathBuf,
-    /// Whether the partition should be writable.
-    #[serde(default)]
-    pub writable: bool,
-}
-
-impl Partition {
-    fn to_parcelable(&self) -> Result<AidlPartition, Error> {
-        Ok(AidlPartition {
-            image: Some(open_parcel_file(&self.path, self.writable)?),
-            writable: self.writable,
-            label: self.label.to_owned(),
-        })
-    }
+fn partition_to_parcelable(partition: &Partition) -> Result<AidlPartition, Error> {
+    Ok(AidlPartition {
+        image: Some(open_parcel_file(&partition.path, partition.writable)?),
+        writable: partition.writable,
+        label: partition.label.to_owned(),
+    })
 }
 
 /// Try to open the given file and wrap it in a [`ParcelFileDescriptor`].
diff --git a/vm/src/main.rs b/vm/src/main.rs
index bdb574c..e2c11a8 100644
--- a/vm/src/main.rs
+++ b/vm/src/main.rs
@@ -19,10 +19,12 @@
 mod sync;
 
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualizationService::IVirtualizationService;
-use android_system_virtualizationservice::binder::{wait_for_interface, ProcessState, Strong};
+use android_system_virtualizationservice::binder::{wait_for_interface, ProcessState, Strong, ParcelFileDescriptor};
 use anyhow::{Context, Error};
 use run::command_run;
-use std::path::PathBuf;
+use std::convert::TryInto;
+use std::fs::OpenOptions;
+use std::path::{PathBuf, Path};
 use structopt::clap::AppSettings;
 use structopt::StructOpt;
 
@@ -49,6 +51,15 @@
     },
     /// List running virtual machines
     List,
+    /// Create a new empty partition to be used as a writable partition for a VM
+    CreatePartition {
+        /// Path at which to create the image file
+        #[structopt(parse(from_os_str))]
+        path: PathBuf,
+
+        /// The desired size of the partition, in bytes.
+        size: u64,
+    },
 }
 
 fn main() -> Result<(), Error> {
@@ -65,6 +76,7 @@
         Opt::Run { config, daemonize } => command_run(service, &config, daemonize),
         Opt::Stop { cid } => command_stop(service, cid),
         Opt::List => command_list(service),
+        Opt::CreatePartition { path, size } => command_create_partition(service, &path, size),
     }
 }
 
@@ -83,3 +95,20 @@
     println!("Running VMs: {:#?}", vms);
     Ok(())
 }
+
+/// Initialise an empty partition image of the given size to be used as a writable partition.
+fn command_create_partition(
+    service: Strong<dyn IVirtualizationService>,
+    image_path: &Path,
+    size: u64,
+) -> Result<(), Error> {
+    let image = OpenOptions::new()
+        .create_new(true)
+        .write(true)
+        .open(image_path)
+        .with_context(|| format!("Failed to create {:?}", image_path))?;
+    service
+        .initializeWritablePartition(&ParcelFileDescriptor::new(image), size.try_into()?)
+        .context("Failed to initialize partition with size {}, size")?;
+    Ok(())
+}