Merge "Set umask in compos_key_cmd."
diff --git a/compos/Android.bp b/compos/Android.bp
index 1eb6716..ba270b8 100644
--- a/compos/Android.bp
+++ b/compos/Android.bp
@@ -67,8 +67,8 @@
 }
 
 rust_binary {
-    name: "compos_key_service",
-    srcs: ["src/compos_key_service.rs"],
+    name: "compos_key_host",
+    srcs: ["src/compos_key_host_main.rs"],
     edition: "2018",
     rustlibs: [
         "compos_aidl_interface-rust",
diff --git a/compos/apex/Android.bp b/compos/apex/Android.bp
index 2dded99..c4ab321 100644
--- a/compos/apex/Android.bp
+++ b/compos/apex/Android.bp
@@ -38,7 +38,7 @@
 
     binaries: [
         "compos_key_cmd",
-        "compos_key_service",
+        "compos_key_host",
         "compsvc",
         "compsvc_worker",
         "pvm_exec",
diff --git a/compos/src/compos_key_host_main.rs b/compos/src/compos_key_host_main.rs
new file mode 100644
index 0000000..28b069a
--- /dev/null
+++ b/compos/src/compos_key_host_main.rs
@@ -0,0 +1,45 @@
+// 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.
+
+//! Run the CompOS key management service in the host, using normal Binder.
+
+mod compos_key_service;
+
+use crate::compos_key_service::CompOsKeyService;
+use anyhow::{Context, Result};
+use compos_aidl_interface::aidl::com::android::compos::ICompOsKeyService::BnCompOsKeyService;
+use compos_aidl_interface::binder::{add_service, BinderFeatures, ProcessState};
+use log::{info, Level};
+
+const LOG_TAG: &str = "CompOsKeyService";
+const OUR_SERVICE_NAME: &str = "android.system.composkeyservice";
+
+fn main() -> Result<()> {
+    android_logger::init_once(
+        android_logger::Config::default().with_tag(LOG_TAG).with_min_level(Level::Trace),
+    );
+
+    // We need to start the thread pool for Binder to work properly.
+    ProcessState::start_thread_pool();
+
+    let service = CompOsKeyService::new()?;
+    let service = BnCompOsKeyService::new_binder(service, BinderFeatures::default());
+
+    add_service(OUR_SERVICE_NAME, service.as_binder()).context("Adding service failed")?;
+    info!("It's alive!");
+
+    ProcessState::join_thread_pool();
+
+    Ok(())
+}
diff --git a/compos/src/compos_key_service.rs b/compos/src/compos_key_service.rs
index 993ef20..654eedd 100644
--- a/compos/src/compos_key_service.rs
+++ b/compos/src/compos_key_service.rs
@@ -27,22 +27,17 @@
 };
 use anyhow::{anyhow, Context, Result};
 use compos_aidl_interface::aidl::com::android::compos::{
-    CompOsKeyData::CompOsKeyData,
-    ICompOsKeyService::{BnCompOsKeyService, ICompOsKeyService},
+    CompOsKeyData::CompOsKeyData, ICompOsKeyService::ICompOsKeyService,
 };
 use compos_aidl_interface::binder::{
-    self, add_service, get_interface, BinderFeatures, ExceptionCode, Interface, ProcessState,
-    Status, Strong,
+    self, wait_for_interface, ExceptionCode, Interface, Status, Strong,
 };
-use log::{info, warn, Level};
+use log::warn;
 use ring::rand::{SecureRandom, SystemRandom};
 use ring::signature;
 use scopeguard::ScopeGuard;
 use std::ffi::CString;
 
-const LOG_TAG: &str = "CompOsKeyService";
-const OUR_SERVICE_NAME: &str = "android.system.composkeyservice";
-
 const KEYSTORE_SERVICE_NAME: &str = "android.system.keystore2.IKeystoreService/default";
 const COMPOS_NAMESPACE: i64 = 101;
 const PURPOSE_SIGN: KeyParameter =
@@ -65,7 +60,7 @@
 const KEY_DESCRIPTOR: KeyDescriptor =
     KeyDescriptor { domain: Domain::BLOB, nspace: COMPOS_NAMESPACE, alias: None, blob: None };
 
-struct CompOsKeyService {
+pub struct CompOsKeyService {
     random: SystemRandom,
     security_level: Strong<dyn IKeystoreSecurityLevel>,
 }
@@ -99,13 +94,16 @@
 }
 
 impl CompOsKeyService {
-    fn new(keystore_service: &Strong<dyn IKeystoreService>) -> Self {
-        Self {
+    pub fn new() -> Result<Self> {
+        let keystore_service = wait_for_interface::<dyn IKeystoreService>(KEYSTORE_SERVICE_NAME)
+            .context("No Keystore service")?;
+
+        Ok(Self {
             random: SystemRandom::new(),
             security_level: keystore_service
                 .getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT)
-                .unwrap(),
-        }
+                .context("Getting SecurityLevel failed")?,
+        })
     }
 
     fn do_generate(&self) -> Result<CompOsKeyData> {
@@ -165,24 +163,3 @@
         signature.ok_or_else(|| anyhow!("No signature returned"))
     }
 }
-
-fn main() -> Result<()> {
-    android_logger::init_once(
-        android_logger::Config::default().with_tag(LOG_TAG).with_min_level(Level::Trace),
-    );
-
-    // We need to start the thread pool for Binder to work properly.
-    ProcessState::start_thread_pool();
-
-    let keystore_service = get_interface::<dyn IKeystoreService>(KEYSTORE_SERVICE_NAME)
-        .context("No Keystore service")?;
-    let service = CompOsKeyService::new(&keystore_service);
-    let service = BnCompOsKeyService::new_binder(service, BinderFeatures::default());
-
-    add_service(OUR_SERVICE_NAME, service.as_binder()).context("Adding service failed")?;
-    info!("It's alive!");
-
-    ProcessState::join_thread_pool();
-
-    Ok(())
-}
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachine.java b/javalib/src/android/system/virtualmachine/VirtualMachine.java
index 3baec94..522651b 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachine.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachine.java
@@ -16,6 +16,8 @@
 
 package android.system.virtualmachine;
 
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+
 import android.content.Context;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
@@ -24,6 +26,7 @@
 import android.system.virtualizationservice.IVirtualMachine;
 import android.system.virtualizationservice.IVirtualMachineCallback;
 import android.system.virtualizationservice.IVirtualizationService;
+import android.system.virtualizationservice.VirtualMachineAppConfig;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -78,9 +81,12 @@
      */
     private final File mConfigFilePath;
 
-    /** Path to the instance image file for this VM. (Not implemented) */
+    /** Path to the instance image file for this VM. */
     private final File mInstanceFilePath;
 
+    /** Size of the instance image. 10 MB. */
+    private static final long INSTANCE_FILE_SIZE = 10 * 1024 * 1024;
+
     /** The configuration that is currently associated with this VM. */
     private VirtualMachineConfig mConfig;
 
@@ -135,7 +141,26 @@
             throw new VirtualMachineException(e);
         }
 
-        // TODO(jiyong): create the instance image file
+        try {
+            vm.mInstanceFilePath.createNewFile();
+        } catch (IOException e) {
+            throw new VirtualMachineException("failed to create instance image", e);
+        }
+
+        IVirtualizationService service =
+                IVirtualizationService.Stub.asInterface(
+                        ServiceManager.waitForService(SERVICE_NAME));
+
+        try {
+            service.initializeWritablePartition(
+                    ParcelFileDescriptor.open(vm.mInstanceFilePath, MODE_READ_WRITE),
+                    INSTANCE_FILE_SIZE);
+        } catch (FileNotFoundException e) {
+            throw new VirtualMachineException("instance image missing", e);
+        } catch (RemoteException e) {
+            throw new VirtualMachineException("failed to create instance partition", e);
+        }
+
         return vm;
     }
 
@@ -144,10 +169,8 @@
             throws VirtualMachineException {
         VirtualMachine vm = new VirtualMachine(context, name, /* config */ null);
 
-        try {
-            FileInputStream input = new FileInputStream(vm.mConfigFilePath);
+        try (FileInputStream input = new FileInputStream(vm.mConfigFilePath)) {
             VirtualMachineConfig config = VirtualMachineConfig.from(input);
-            input.close();
             vm.mConfig = config;
         } catch (FileNotFoundException e) {
             // The VM doesn't exist.
@@ -156,6 +179,13 @@
             throw new VirtualMachineException(e);
         }
 
+        // If config file exists, but the instance image file doesn't, it means that the VM is
+        // corrupted. That's different from the case that the VM doesn't exist. Throw an exception
+        // instead of returning null.
+        if (!vm.mInstanceFilePath.exists()) {
+            throw new VirtualMachineException("instance image missing");
+        }
+
         return vm;
     }
 
@@ -225,12 +255,14 @@
                 mConsoleReader = pipe[0];
                 mConsoleWriter = pipe[1];
             }
-            mVirtualMachine =
-                    service.startVm(
-                            android.system.virtualizationservice.VirtualMachineConfig.appConfig(
-                                    getConfig().toParcel()),
-                            mConsoleWriter);
 
+            VirtualMachineAppConfig appConfig = getConfig().toParcel();
+            appConfig.instanceImage = ParcelFileDescriptor.open(mInstanceFilePath, MODE_READ_WRITE);
+
+            android.system.virtualizationservice.VirtualMachineConfig vmConfigParcel =
+                    android.system.virtualizationservice.VirtualMachineConfig.appConfig(appConfig);
+
+            mVirtualMachine = service.startVm(vmConfigParcel, mConsoleWriter);
             mVirtualMachine.registerCallback(
                     new IVirtualMachineCallback.Stub() {
                         @Override
diff --git a/microdroid/sepolicy/system/private/domain.te b/microdroid/sepolicy/system/private/domain.te
index da811ed..fe4d072 100644
--- a/microdroid/sepolicy/system/private/domain.te
+++ b/microdroid/sepolicy/system/private/domain.te
@@ -68,6 +68,8 @@
 
 allow domain property_contexts_file:file r_file_perms;
 
+dontaudit domain property_type:file audit_access;
+
 allow domain init:key search;
 
 # logd access
diff --git a/tests/hostside/helper/java/android/virt/test/VirtualizationTestCaseBase.java b/tests/hostside/helper/java/android/virt/test/VirtualizationTestCaseBase.java
index 451f9ba..2d55a9c 100644
--- a/tests/hostside/helper/java/android/virt/test/VirtualizationTestCaseBase.java
+++ b/tests/hostside/helper/java/android/virt/test/VirtualizationTestCaseBase.java
@@ -43,6 +43,7 @@
     private static final String VIRT_APEX = "/apex/com.android.virt/";
     private static final int TEST_VM_ADB_PORT = 8000;
     private static final String MICRODROID_SERIAL = "localhost:" + TEST_VM_ADB_PORT;
+    private static final String INSTANCE_IMG = "instance.img";
 
     // This is really slow on GCE (2m 40s) but fast on localhost or actual Android phones (< 10s)
     // Set the maximum timeout value big enough.
@@ -192,6 +193,7 @@
         final String apkIdsigPath = TEST_ROOT + apkName + ".idsig";
         getDevice().pushFile(idsigOnHost, apkIdsigPath);
 
+        final String instanceImg = TEST_ROOT + INSTANCE_IMG;
         final String logPath = TEST_ROOT + "log.txt";
         final String debugFlag = debug ? "--debug " : "";
 
@@ -206,6 +208,7 @@
                         debugFlag,
                         apkPath,
                         apkIdsigPath,
+                        instanceImg,
                         configPath);
 
         // Redirect log.txt to logd using logwrapper
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
index 4dcfb88..a5f7c3c 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
@@ -23,6 +23,9 @@
     /** idsig for an APK */
     ParcelFileDescriptor idsig;
 
+    /** instance.img that has per-instance data */
+    ParcelFileDescriptor instanceImage;
+
     /** Path to a configuration in an APK. This is the actual configuration for a VM. */
     @utf8InCpp String configPath;
 
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 3ebde6f..44d89e7 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -339,6 +339,8 @@
 ) -> Result<VirtualMachineRawConfig> {
     let apk_file = config.apk.as_ref().unwrap().as_ref();
     let idsig_file = config.idsig.as_ref().unwrap().as_ref();
+    // TODO(b/193504400) pass this to crosvm
+    let _instance_file = config.instanceImage.as_ref().unwrap().as_ref();
     let config_path = &config.configPath;
 
     let mut apk_zip = ZipArchive::new(apk_file)?;
diff --git a/vm/src/create_partition.rs b/vm/src/create_partition.rs
new file mode 100644
index 0000000..acebbf2
--- /dev/null
+++ b/vm/src/create_partition.rs
@@ -0,0 +1,40 @@
+// 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.
+
+//! Command to create an empty partition
+
+use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualizationService::IVirtualizationService;
+use android_system_virtualizationservice::binder::{ParcelFileDescriptor, Strong};
+use anyhow::{Context, Error};
+use std::convert::TryInto;
+use std::fs::OpenOptions;
+use std::path::Path;
+
+/// Initialise an empty partition image of the given size to be used as a writable partition.
+pub fn command_create_partition(
+    service: Strong<dyn IVirtualizationService>,
+    image_path: &Path,
+    size: u64,
+) -> Result<(), Error> {
+    let image = OpenOptions::new()
+        .create_new(true)
+        .read(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(())
+}
diff --git a/vm/src/main.rs b/vm/src/main.rs
index 9ca0ea6..09f11d5 100644
--- a/vm/src/main.rs
+++ b/vm/src/main.rs
@@ -14,16 +14,16 @@
 
 //! Android VM control tool.
 
+mod create_partition;
 mod run;
 mod sync;
 
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualizationService::IVirtualizationService;
-use android_system_virtualizationservice::binder::{wait_for_interface, ProcessState, Strong, ParcelFileDescriptor};
+use android_system_virtualizationservice::binder::{wait_for_interface, ProcessState, Strong};
 use anyhow::{Context, Error};
+use create_partition::command_create_partition;
 use run::{command_run, command_run_app};
-use std::convert::TryInto;
-use std::fs::OpenOptions;
-use std::path::{PathBuf, Path};
+use std::path::PathBuf;
 use structopt::clap::AppSettings;
 use structopt::StructOpt;
 
@@ -43,6 +43,10 @@
         #[structopt(parse(from_os_str))]
         idsig: PathBuf,
 
+        /// Path to the instance image. Created if not exists.
+        #[structopt(parse(from_os_str))]
+        instance: PathBuf,
+
         /// Path to VM config JSON within APK (e.g. assets/vm_config.json)
         config_path: String,
 
@@ -101,8 +105,17 @@
         .context("Failed to find VirtualizationService")?;
 
     match opt {
-        Opt::RunApp { apk, idsig, config_path, daemonize, log, debug } => {
-            command_run_app(service, &apk, &idsig, &config_path, daemonize, log.as_deref(), debug)
+        Opt::RunApp { apk, idsig, instance, config_path, daemonize, log, debug } => {
+            command_run_app(
+                service,
+                &apk,
+                &idsig,
+                &instance,
+                &config_path,
+                daemonize,
+                log.as_deref(),
+                debug,
+            )
         }
         Opt::Run { config, daemonize, log } => {
             command_run(service, &config, daemonize, log.as_deref())
@@ -128,21 +141,3 @@
     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)
-        .read(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(())
-}
diff --git a/vm/src/run.rs b/vm/src/run.rs
index 184a396..41fdabb 100644
--- a/vm/src/run.rs
+++ b/vm/src/run.rs
@@ -14,6 +14,7 @@
 
 //! Command to run a VM.
 
+use crate::create_partition::command_create_partition;
 use crate::sync::AtomicFlag;
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualizationService::IVirtualizationService;
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualMachine::IVirtualMachine;
@@ -33,13 +34,15 @@
 use std::io::{self, BufRead, BufReader};
 use std::os::unix::io::{AsRawFd, FromRawFd};
 use std::path::Path;
-use vmconfig::VmConfig;
+use vmconfig::{open_parcel_file, VmConfig};
 
 /// Run a VM from the given APK, idsig, and config.
+#[allow(clippy::too_many_arguments)]
 pub fn command_run_app(
     service: Strong<dyn IVirtualizationService>,
     apk: &Path,
     idsig: &Path,
+    instance: &Path,
     config_path: &str,
     daemonize: bool,
     log_path: Option<&Path>,
@@ -47,9 +50,16 @@
 ) -> Result<(), Error> {
     let apk_file = File::open(apk).context("Failed to open APK file")?;
     let idsig_file = File::open(idsig).context("Failed to open idsig file")?;
+
+    if !instance.exists() {
+        const INSTANCE_FILE_SIZE: u64 = 10 * 1024 * 1024;
+        command_create_partition(service.clone(), instance, INSTANCE_FILE_SIZE)?;
+    }
+
     let config = VirtualMachineConfig::AppConfig(VirtualMachineAppConfig {
         apk: ParcelFileDescriptor::new(apk_file).into(),
         idsig: ParcelFileDescriptor::new(idsig_file).into(),
+        instanceImage: open_parcel_file(instance, true /* writable */)?.into(),
         configPath: config_path.to_owned(),
         debug,
     });
diff --git a/vmconfig/src/lib.rs b/vmconfig/src/lib.rs
index 1a16d30..4a5b3b1 100644
--- a/vmconfig/src/lib.rs
+++ b/vmconfig/src/lib.rs
@@ -153,7 +153,7 @@
 }
 
 /// Try to open the given file and wrap it in a [`ParcelFileDescriptor`].
-fn open_parcel_file(filename: &Path, writable: bool) -> Result<ParcelFileDescriptor> {
+pub fn open_parcel_file(filename: &Path, writable: bool) -> Result<ParcelFileDescriptor> {
     Ok(ParcelFileDescriptor::new(
         OpenOptions::new()
             .read(true)