Create QCOW2 image rather than raw for writable partitions.

Bug: 190503448
Test: vm create-partition /data/local/tmp/blah 1000000
Change-Id: Iff9269d71ea3e5dcff5fbfd1f5a62abfa4633bc0
diff --git a/apex/Android.bp b/apex/Android.bp
index 3db4c1a..bcc7099 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -13,12 +13,13 @@
     key: "com.android.virt.key",
     certificate: ":com.android.virt.certificate",
 
-    // crosvm is enabled for only 64-bit targets on device
+    // crosvm and virtualizationservice are only enabled for 64-bit targets on device
     arch: {
         arm64: {
             binaries: [
                 "authfs", // TODO(victorhsieh): move to microdroid once we can run the test in VM.
                 "crosvm",
+                "virtualizationservice",
             ],
             filesystems: [
                 "microdroid_super",
@@ -32,6 +33,7 @@
             binaries: [
                 "authfs", // TODO(victorhsieh): move to microdroid once we can run the test in VM.
                 "crosvm",
+                "virtualizationservice",
             ],
             filesystems: [
                 "microdroid_super",
@@ -44,7 +46,6 @@
     },
     binaries: [
         "fd_server",
-        "virtualizationservice",
         "vm",
 
         // tools to create composite images
diff --git a/virtualizationservice/Android.bp b/virtualizationservice/Android.bp
index bad7f46..f5ad1f8 100644
--- a/virtualizationservice/Android.bp
+++ b/virtualizationservice/Android.bp
@@ -7,6 +7,17 @@
     crate_name: "virtualizationservice",
     srcs: ["src/main.rs"],
     edition: "2018",
+    // Only build on targets which crosvm builds on.
+    enabled: false,
+    target: {
+        android64: {
+            compile_multilib: "64",
+            enabled: true,
+        },
+        linux_bionic_arm64: {
+            enabled: true,
+        },
+    },
     prefer_rlib: true,
     rustlibs: [
         "android.system.virtualizationservice-rust",
@@ -14,6 +25,7 @@
         "libanyhow",
         "libcommand_fds",
         "libcompositediskconfig",
+        "libdisk",
         "liblog_rust",
         "libserde_json",
         "libserde",
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
index 311c2e0..8affaad 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
@@ -27,7 +27,11 @@
     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. */
+    /**
+     * Initialise an empty partition image of the given size to be used as a writable partition.
+     *
+     * The file must be open with both read and write permissions, and should be a new empty file.
+     */
     void initializeWritablePartition(in ParcelFileDescriptor imageFd, long size);
 
     /**
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 7b63917..bc8df9d 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -29,10 +29,10 @@
     self, BinderFeatures, Interface, ParcelFileDescriptor, StatusCode, Strong, ThreadState,
 };
 use command_fds::FdMapping;
+use disk::QcowFile;
 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};
@@ -139,26 +139,16 @@
         image_fd: &ParcelFileDescriptor,
         size: i64,
     ) -> binder::Result<()> {
-        let size: u64 = size.try_into().map_err(|e| {
+        let size = size.try_into().map_err(|e| {
             error!("Invalid size {}: {}", size, e);
             StatusCode::BAD_VALUE
         })?;
-        let mut image = clone_file(image_fd)?;
+        let 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
-            })?;
-        }
+        QcowFile::new(image, size).map_err(|e| {
+            error!("Failed to create QCOW2 image: {}", e);
+            StatusCode::UNKNOWN_ERROR
+        })?;
 
         Ok(())
     }
diff --git a/vm/src/main.rs b/vm/src/main.rs
index e2c11a8..2c93ec4 100644
--- a/vm/src/main.rs
+++ b/vm/src/main.rs
@@ -104,6 +104,7 @@
 ) -> Result<(), Error> {
     let image = OpenOptions::new()
         .create_new(true)
+        .read(true)
         .write(true)
         .open(image_path)
         .with_context(|| format!("Failed to create {:?}", image_path))?;