Format instance.img

When instance.img is created by VS, it's header is formatted to have the
magic number and the version field correctly set.

Bug: 193504400
Test: od -t x /dev/block/by-name/vm-instance shows the magic number and
the version number.

Change-Id: Ie2a04c648a2d8d239aa305660e4408fb0ffc2c33
diff --git a/compos/compos_key_cmd/compos_key_cmd.cpp b/compos/compos_key_cmd/compos_key_cmd.cpp
index 04ba1d0..4d69d53 100644
--- a/compos/compos_key_cmd/compos_key_cmd.cpp
+++ b/compos/compos_key_cmd/compos_key_cmd.cpp
@@ -54,6 +54,7 @@
 using aidl::android::system::virtualizationservice::IVirtualizationService;
 using aidl::android::system::virtualizationservice::IVirtualMachine;
 using aidl::android::system::virtualizationservice::IVirtualMachineCallback;
+using aidl::android::system::virtualizationservice::PartitionType;
 using aidl::android::system::virtualizationservice::VirtualMachineConfig;
 using aidl::com::android::compos::CompOsKeyData;
 using aidl::com::android::compos::ICompOsService;
@@ -442,7 +443,8 @@
         return ErrnoError() << "Failed to create image file";
     }
 
-    auto status = service->initializeWritablePartition(fd, 10 * 1024 * 1024);
+    auto status = service->initializeWritablePartition(fd, 10 * 1024 * 1024,
+                                                       PartitionType::ANDROID_VM_INSTANCE);
     if (!status.isOk()) {
         return Error() << "Failed to initialize partition: " << status.getDescription();
     }
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachine.java b/javalib/src/android/system/virtualmachine/VirtualMachine.java
index 3152c3b..959e355 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachine.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachine.java
@@ -29,6 +29,7 @@
 import android.system.virtualizationservice.IVirtualMachine;
 import android.system.virtualizationservice.IVirtualMachineCallback;
 import android.system.virtualizationservice.IVirtualizationService;
+import android.system.virtualizationservice.PartitionType;
 import android.system.virtualizationservice.VirtualMachineAppConfig;
 
 import java.io.File;
@@ -165,7 +166,8 @@
         try {
             service.initializeWritablePartition(
                     ParcelFileDescriptor.open(vm.mInstanceFilePath, MODE_READ_WRITE),
-                    INSTANCE_FILE_SIZE);
+                    INSTANCE_FILE_SIZE,
+                    PartitionType.ANDROID_VM_INSTANCE);
         } catch (FileNotFoundException e) {
             throw new VirtualMachineException("instance image missing", e);
         } catch (RemoteException e) {
@@ -288,7 +290,6 @@
             android.system.virtualizationservice.VirtualMachineConfig vmConfigParcel =
                     android.system.virtualizationservice.VirtualMachineConfig.appConfig(appConfig);
 
-
             mVirtualMachine = service.startVm(vmConfigParcel, mConsoleWriter);
             mVirtualMachine.registerCallback(
                     new IVirtualMachineCallback.Stub() {
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
index d136465..7c4b897 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
@@ -16,6 +16,7 @@
 package android.system.virtualizationservice;
 
 import android.system.virtualizationservice.IVirtualMachine;
+import android.system.virtualizationservice.PartitionType;
 import android.system.virtualizationservice.VirtualMachineConfig;
 import android.system.virtualizationservice.VirtualMachineDebugInfo;
 
@@ -32,7 +33,8 @@
      *
      * 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);
+    void initializeWritablePartition(
+            in ParcelFileDescriptor imageFd, long size, PartitionType type);
 
     /**
      * Create or update an idsig file that digests the given APK file. The idsig file follows the
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/PartitionType.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/PartitionType.aidl
new file mode 100644
index 0000000..f25e674
--- /dev/null
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/PartitionType.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.system.virtualizationservice;
+
+/**
+ * Type of the writable partition that virtualizationservice creates via
+ * initializeWritablePartition.
+ */
+@Backing(type="int")
+enum PartitionType {
+    /**
+     * The partition is simply initialized as all zeros
+     */
+    RAW = 0,
+    /**
+     * The partition is initialized as an instance image which is formatted to hold per-VM secrets
+     */
+    ANDROID_VM_INSTANCE = 1,
+}
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 23a9c03..ff5298c 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -32,6 +32,7 @@
     VirtualMachineRawConfig::VirtualMachineRawConfig,
 };
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::VirtualMachineDebugInfo::VirtualMachineDebugInfo;
+use android_system_virtualizationservice::aidl::android::system::virtualizationservice::PartitionType::PartitionType;
 use android_system_virtualizationservice::binder::{
     self, BinderFeatures, ExceptionCode, Interface, ParcelFileDescriptor, Status, Strong, ThreadState,
 };
@@ -43,6 +44,7 @@
 use std::convert::TryInto;
 use std::ffi::CString;
 use std::fs::{File, OpenOptions, create_dir};
+use std::io::{Error, ErrorKind, Write};
 use std::num::NonZeroU32;
 use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
 use std::path::{Path, PathBuf};
@@ -67,6 +69,12 @@
 /// Gaps in composite disk images are filled with a shared zero.img.
 const ZERO_FILLER_SIZE: u64 = 4096;
 
+/// Magic string for the instance image
+const ANDROID_VM_INSTANCE_MAGIC: &str = "Android-VM-instance";
+
+/// Version of the instance image format
+const ANDROID_VM_INSTANCE_VERSION: u16 = 1;
+
 /// Implementation of `IVirtualizationService`, the entry point of the AIDL service.
 #[derive(Debug, Default)]
 pub struct VirtualizationService {
@@ -190,6 +198,7 @@
         &self,
         image_fd: &ParcelFileDescriptor,
         size: i64,
+        partition_type: PartitionType,
     ) -> binder::Result<()> {
         check_manage_access()?;
         let size = size.try_into().map_err(|e| {
@@ -200,13 +209,28 @@
         })?;
         let image = clone_file(image_fd)?;
 
-        QcowFile::new(image, size).map_err(|e| {
+        let mut part = QcowFile::new(image, size).map_err(|e| {
             new_binder_exception(
                 ExceptionCode::SERVICE_SPECIFIC,
                 format!("Failed to create QCOW2 image: {}", e),
             )
         })?;
 
+        match partition_type {
+            PartitionType::RAW => Ok(()),
+            PartitionType::ANDROID_VM_INSTANCE => format_as_android_vm_instance(&mut part),
+            _ => Err(Error::new(
+                ErrorKind::Unsupported,
+                format!("Unsupported partition type {:?}", partition_type),
+            )),
+        }
+        .map_err(|e| {
+            new_binder_exception(
+                ExceptionCode::SERVICE_SPECIFIC,
+                format!("Failed to initialize partition as {:?}: {}", partition_type, e),
+            )
+        })?;
+
         Ok(())
     }
 
@@ -320,6 +344,12 @@
     Ok(())
 }
 
+fn format_as_android_vm_instance(part: &mut dyn Write) -> std::io::Result<()> {
+    part.write_all(ANDROID_VM_INSTANCE_MAGIC.as_bytes())?;
+    part.write_all(&ANDROID_VM_INSTANCE_VERSION.to_le_bytes())?;
+    part.flush()
+}
+
 /// Given the configuration for a disk image, assembles the `DiskFile` to pass to crosvm.
 ///
 /// This may involve assembling a composite disk from a set of partition images.
diff --git a/vm/src/create_partition.rs b/vm/src/create_partition.rs
index acebbf2..22f7bea 100644
--- a/vm/src/create_partition.rs
+++ b/vm/src/create_partition.rs
@@ -15,6 +15,7 @@
 //! Command to create an empty partition
 
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualizationService::IVirtualizationService;
+use android_system_virtualizationservice::aidl::android::system::virtualizationservice::PartitionType::PartitionType;
 use android_system_virtualizationservice::binder::{ParcelFileDescriptor, Strong};
 use anyhow::{Context, Error};
 use std::convert::TryInto;
@@ -26,6 +27,7 @@
     service: Strong<dyn IVirtualizationService>,
     image_path: &Path,
     size: u64,
+    partition_type: PartitionType,
 ) -> Result<(), Error> {
     let image = OpenOptions::new()
         .create_new(true)
@@ -34,7 +36,14 @@
         .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")?;
+        .initializeWritablePartition(
+            &ParcelFileDescriptor::new(image),
+            size.try_into()?,
+            partition_type,
+        )
+        .context(format!(
+            "Failed to initialize partition type: {:?}, size: {}",
+            partition_type, size
+        ))?;
     Ok(())
 }
diff --git a/vm/src/main.rs b/vm/src/main.rs
index 09f11d5..fe47d2c 100644
--- a/vm/src/main.rs
+++ b/vm/src/main.rs
@@ -19,6 +19,7 @@
 mod sync;
 
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualizationService::IVirtualizationService;
+use android_system_virtualizationservice::aidl::android::system::virtualizationservice::PartitionType::PartitionType;
 use android_system_virtualizationservice::binder::{wait_for_interface, ProcessState, Strong};
 use anyhow::{Context, Error};
 use create_partition::command_create_partition;
@@ -91,9 +92,21 @@
 
         /// The desired size of the partition, in bytes.
         size: u64,
+
+        /// Type of the partition
+        #[structopt(short="t", long="type", default_value="raw", parse(try_from_str=parse_partition_type))]
+        partition_type: PartitionType,
     },
 }
 
+fn parse_partition_type(s: &str) -> Result<PartitionType, String> {
+    match s {
+        "raw" => Ok(PartitionType::RAW),
+        "instance" => Ok(PartitionType::ANDROID_VM_INSTANCE),
+        _ => Err(format!("Invalid partition type {}", s)),
+    }
+}
+
 fn main() -> Result<(), Error> {
     env_logger::init();
     let opt = Opt::from_args();
@@ -122,7 +135,9 @@
         }
         Opt::Stop { cid } => command_stop(service, cid),
         Opt::List => command_list(service),
-        Opt::CreatePartition { path, size } => command_create_partition(service, &path, size),
+        Opt::CreatePartition { path, size, partition_type } => {
+            command_create_partition(service, &path, size, partition_type)
+        }
     }
 }
 
diff --git a/vm/src/run.rs b/vm/src/run.rs
index 8db43fb..2878f21 100644
--- a/vm/src/run.rs
+++ b/vm/src/run.rs
@@ -22,6 +22,7 @@
     BnVirtualMachineCallback, IVirtualMachineCallback,
 };
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
+    PartitionType::PartitionType,
     VirtualMachineAppConfig::VirtualMachineAppConfig,
     VirtualMachineConfig::VirtualMachineConfig,
 };
@@ -60,7 +61,12 @@
 
     if !instance.exists() {
         const INSTANCE_FILE_SIZE: u64 = 10 * 1024 * 1024;
-        command_create_partition(service.clone(), instance, INSTANCE_FILE_SIZE)?;
+        command_create_partition(
+            service.clone(),
+            instance,
+            INSTANCE_FILE_SIZE,
+            PartitionType::ANDROID_VM_INSTANCE,
+        )?;
     }
 
     let config = VirtualMachineConfig::AppConfig(VirtualMachineAppConfig {