Merge "Update init_first_stage"
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..b655551
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 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 {
+    default_applicable_licenses: ["packages_modules_Virtualization_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "packages_modules_Virtualization_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "legacy_unencumbered",
+    ],
+    // large-scale-change unable to identify any license_text files
+}
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..13c68d7
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,21 @@
+{
+  "postsubmit": [
+    {
+      "name": "MicrodroidHostTestCases"
+    },
+    {
+      "name": "VirtualizationTestCases"
+    }
+  ],
+  "imports": [
+    {
+      "path": "packages/modules/Virtualization/apkdmverity"
+    },
+    {
+      "path": "packages/modules/Virtualization/authfs"
+    },
+    {
+      "path": "packages/modules/Virtualization/zipfuse"
+    }
+  ]
+}
diff --git a/apex/Android.bp b/apex/Android.bp
index 3db4c1a..146e4eb 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,23 +46,16 @@
     },
     binaries: [
         "fd_server",
-        "virtualizationservice",
         "vm",
 
         // tools to create composite images
         "mk_cdisk",
         "mk_payload",
     ],
-    apps: [
-        // TODO(jiyong): remove this when microdroid_payload.json is created by
-        // VirtualizationService.
-        "MicrodroidTestApp",
-    ],
     prebuilts: [
         "com.android.virt.init.rc",
         "microdroid_cdisk.json",
         "microdroid_cdisk_env.json",
-        "microdroid_payload.json",
         "microdroid_uboot_env",
         "microdroid_bootloader",
     ],
diff --git a/apkdmverity/src/loopdevice.rs b/apkdmverity/src/loopdevice.rs
index 69920d5..376abd4 100644
--- a/apkdmverity/src/loopdevice.rs
+++ b/apkdmverity/src/loopdevice.rs
@@ -37,7 +37,8 @@
 
 // These are old-style ioctls, thus *_bad.
 nix::ioctl_none_bad!(_loop_ctl_get_free, LOOP_CTL_GET_FREE);
-nix::ioctl_write_ptr_bad!(_loop_configure, LOOP_CONFIGURE, loop_config);
+nix::ioctl_write_int_bad!(_loop_set_fd, LOOP_SET_FD);
+nix::ioctl_write_ptr_bad!(_loop_set_status64, LOOP_SET_STATUS64, loop_info64);
 #[cfg(test)]
 nix::ioctl_none_bad!(_loop_clr_fd, LOOP_CLR_FD);
 
@@ -48,9 +49,14 @@
     Ok(unsafe { _loop_ctl_get_free(ctrl_file.as_raw_fd()) }?)
 }
 
-fn loop_configure(device_file: &File, config: &loop_config) -> Result<i32> {
+fn loop_set_fd(device_file: &File, fd: i32) -> Result<i32> {
     // SAFETY: this ioctl changes the state in kernel, but not the state in this process.
-    Ok(unsafe { _loop_configure(device_file.as_raw_fd(), config) }?)
+    Ok(unsafe { _loop_set_fd(device_file.as_raw_fd(), fd) }?)
+}
+
+fn loop_set_status64(device_file: &File, info: &loop_info64) -> Result<i32> {
+    // SAFETY: this ioctl changes the state in kernel, but not the state in this process.
+    Ok(unsafe { _loop_set_status64(device_file.as_raw_fd(), info) }?)
 }
 
 #[cfg(test)]
@@ -103,26 +109,24 @@
         .context("Failed to open loop control")?;
     let num = loop_ctl_get_free(&ctrl_file).context("Failed to get free loop device")?;
 
-    // Construct the loop_config struct
+    // Construct the loop_info64 struct
     let backing_file = OpenOptions::new()
         .read(true)
         .open(&path)
         .context(format!("failed to open {:?}", path.as_ref()))?;
     // safe because the size of the array is the same as the size of the struct
-    let mut config: loop_config =
-        *DataInit::from_mut_slice(&mut [0; size_of::<loop_config>()]).unwrap();
-    config.fd = backing_file.as_raw_fd() as u32;
-    config.block_size = 4096;
-    config.info.lo_offset = offset;
-    config.info.lo_sizelimit = size_limit;
-    config.info.lo_flags |= Flag::LO_FLAGS_DIRECT_IO | Flag::LO_FLAGS_READ_ONLY;
+    let mut info: loop_info64 =
+        *DataInit::from_mut_slice(&mut [0; size_of::<loop_info64>()]).unwrap();
+    info.lo_offset = offset;
+    info.lo_sizelimit = size_limit;
+    info.lo_flags |= Flag::LO_FLAGS_DIRECT_IO | Flag::LO_FLAGS_READ_ONLY;
 
     // Special case: don't use direct IO when the backing file is already a loop device, which
     // happens only during test. DirectIO-on-loop-over-loop makes the outer loop device
     // unaccessible.
     #[cfg(test)]
     if path.as_ref().to_str().unwrap().starts_with(LOOP_DEV_PREFIX) {
-        config.info.lo_flags.remove(Flag::LO_FLAGS_DIRECT_IO);
+        info.lo_flags.remove(Flag::LO_FLAGS_DIRECT_IO);
     }
 
     // Configure the loop device to attach the backing file
@@ -133,8 +137,8 @@
         .write(true)
         .open(&device_path)
         .context(format!("failed to open {:?}", &device_path))?;
-    loop_configure(&device_file, &config)
-        .context(format!("Failed to configure {:?}", &device_path))?;
+    loop_set_fd(&device_file, backing_file.as_raw_fd() as i32)?;
+    loop_set_status64(&device_file, &info)?;
 
     Ok(PathBuf::from(device_path))
 }
diff --git a/apkdmverity/src/loopdevice/sys.rs b/apkdmverity/src/loopdevice/sys.rs
index 5de0c92..d32987a 100644
--- a/apkdmverity/src/loopdevice/sys.rs
+++ b/apkdmverity/src/loopdevice/sys.rs
@@ -24,7 +24,8 @@
 pub const LOOP_CONTROL: &str = "/dev/loop-control";
 
 pub const LOOP_CTL_GET_FREE: libc::c_ulong = 0x4C82;
-pub const LOOP_CONFIGURE: libc::c_ulong = 0x4C0A;
+pub const LOOP_SET_FD: libc::c_ulong = 0x4C00;
+pub const LOOP_SET_STATUS64: libc::c_ulong = 0x4C04;
 #[cfg(test)]
 pub const LOOP_CLR_FD: libc::c_ulong = 0x4C01;
 
@@ -58,6 +59,9 @@
     pub lo_init: [u64; 2],
 }
 
+// SAFETY: C struct is safe to be initialized from raw data
+unsafe impl DataInit for loop_info64 {}
+
 bitflags! {
     pub struct Flag: u32 {
         const LO_FLAGS_READ_ONLY = 1 << 0;
diff --git a/apkdmverity/src/main.rs b/apkdmverity/src/main.rs
index 5094c50..54d5def 100644
--- a/apkdmverity/src/main.rs
+++ b/apkdmverity/src/main.rs
@@ -37,7 +37,7 @@
 use std::path::{Path, PathBuf};
 
 fn main() -> Result<()> {
-    let matches = App::new("apkverity")
+    let matches = App::new("apkdmverity")
         .about("Creates a dm-verity block device out of APK signed with APK signature scheme V4.")
         .arg(
             Arg::with_name("apk")
diff --git a/authfs/Android.bp b/authfs/Android.bp
index 16d0b3a..174914f 100644
--- a/authfs/Android.bp
+++ b/authfs/Android.bp
@@ -14,6 +14,8 @@
         "libandroid_logger",
         "libanyhow",
         "libauthfs_crypto_bindgen",
+        "libbinder_rpc_unstable_bindgen",
+        "libbinder_rs",
         "libcfg_if",
         "libfuse_rust",
         "liblibc",
@@ -27,7 +29,10 @@
             enabled: false,
         },
     },
-    shared_libs: ["libcrypto"],
+    shared_libs: [
+        "libcrypto",
+        "libbinder_rpc_unstable",
+    ],
     defaults: ["crosvm_defaults"],
 }
 
diff --git a/authfs/fd_server/Android.bp b/authfs/fd_server/Android.bp
index 748a5b6..8ddbf69 100644
--- a/authfs/fd_server/Android.bp
+++ b/authfs/fd_server/Android.bp
@@ -9,11 +9,16 @@
         "authfs_aidl_interface-rust",
         "libandroid_logger",
         "libanyhow",
+        "libbinder_rpc_unstable_bindgen",
+        "libbinder_rs",
         "libclap",
         "liblibc",
         "liblog_rust",
         "libnix",
     ],
     prefer_rlib: true,
+    shared_libs: [
+        "libbinder_rpc_unstable",
+    ],
     apex_available: ["com.android.virt"],
 }
diff --git a/authfs/fd_server/src/main.rs b/authfs/fd_server/src/main.rs
index 204d1b1..5137a2e 100644
--- a/authfs/fd_server/src/main.rs
+++ b/authfs/fd_server/src/main.rs
@@ -37,6 +37,7 @@
 use std::os::unix::io::{AsRawFd, FromRawFd};
 
 use anyhow::{bail, Context, Result};
+use binder::unstable_api::AsNative;
 use log::{debug, error};
 
 use authfs_aidl_interface::aidl::com::android::virt::fs::IVirtFdService::{
@@ -48,6 +49,7 @@
 };
 
 const SERVICE_NAME: &str = "authfs_fd_server";
+const RPC_SERVICE_PORT: u32 = 3264; // TODO: support dynamic port for multiple fd_server instances
 
 fn new_binder_exception<T: AsRef<str>>(exception: ExceptionCode, message: T) -> Status {
     Status::new_exception(exception, CString::new(message.as_ref()).as_deref().ok())
@@ -275,7 +277,7 @@
     Ok((fd, FdConfig::ReadWrite(file)))
 }
 
-fn parse_args() -> Result<BTreeMap<i32, FdConfig>> {
+fn parse_args() -> Result<(bool, BTreeMap<i32, FdConfig>)> {
     #[rustfmt::skip]
     let matches = clap::App::new("fd_server")
         .arg(clap::Arg::with_name("ro-fds")
@@ -286,6 +288,8 @@
              .long("rw-fds")
              .multiple(true)
              .number_of_values(1))
+        .arg(clap::Arg::with_name("rpc-binder")
+             .long("rpc-binder"))
         .get_matches();
 
     let mut fd_pool = BTreeMap::new();
@@ -301,7 +305,9 @@
             fd_pool.insert(fd, config);
         }
     }
-    Ok(fd_pool)
+
+    let rpc_binder = matches.is_present("rpc-binder");
+    Ok((rpc_binder, fd_pool))
 }
 
 fn main() -> Result<()> {
@@ -309,14 +315,32 @@
         android_logger::Config::default().with_tag("fd_server").with_min_level(log::Level::Debug),
     );
 
-    let fd_pool = parse_args()?;
+    let (rpc_binder, fd_pool) = parse_args()?;
 
-    ProcessState::start_thread_pool();
-
-    add_service(SERVICE_NAME, FdService::new_binder(fd_pool).as_binder())
-        .with_context(|| format!("Failed to register service {}", SERVICE_NAME))?;
-    debug!("fd_server is running.");
-
-    ProcessState::join_thread_pool();
-    bail!("Unexpected exit after join_thread_pool")
+    if rpc_binder {
+        let mut service = FdService::new_binder(fd_pool).as_binder();
+        debug!("fd_server is starting as a rpc service.");
+        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+        // Plus the binder objects are threadsafe.
+        let retval = unsafe {
+            binder_rpc_unstable_bindgen::RunRpcServer(
+                service.as_native_mut() as *mut binder_rpc_unstable_bindgen::AIBinder,
+                RPC_SERVICE_PORT,
+            )
+        };
+        if retval {
+            debug!("RPC server has shut down gracefully");
+            Ok(())
+        } else {
+            bail!("Premature termination of RPC server");
+        }
+    } else {
+        ProcessState::start_thread_pool();
+        let service = FdService::new_binder(fd_pool).as_binder();
+        add_service(SERVICE_NAME, service)
+            .with_context(|| format!("Failed to register service {}", SERVICE_NAME))?;
+        debug!("fd_server is running as a local service.");
+        ProcessState::join_thread_pool();
+        bail!("Unexpected exit after join_thread_pool")
+    }
 }
diff --git a/authfs/src/file.rs b/authfs/src/file.rs
index 4b43786..033dbd6 100644
--- a/authfs/src/file.rs
+++ b/authfs/src/file.rs
@@ -4,21 +4,56 @@
 pub use local_file::LocalFileReader;
 pub use remote_file::{RemoteFileEditor, RemoteFileReader, RemoteMerkleTreeReader};
 
+use binder::unstable_api::{new_spibinder, AIBinder};
+use binder::FromIBinder;
 use std::io;
 
 use crate::common::CHUNK_SIZE;
-
-use authfs_aidl_interface::aidl::com::android::virt::fs::IVirtFdService;
+use authfs_aidl_interface::aidl::com::android::virt::fs::IVirtFdService::IVirtFdService;
 use authfs_aidl_interface::binder::{get_interface, Strong};
 
-// TODO(victorhsieh): use remote binder.
-pub fn get_local_binder() -> Strong<dyn IVirtFdService::IVirtFdService> {
-    let service_name = "authfs_fd_server";
-    get_interface(&service_name).expect("Cannot reach authfs_fd_server binder service")
-}
+pub type VirtFdService = Strong<dyn IVirtFdService>;
 
 pub type ChunkBuffer = [u8; CHUNK_SIZE as usize];
 
+pub const RPC_SERVICE_PORT: u32 = 3264;
+
+fn get_local_binder() -> io::Result<VirtFdService> {
+    let service_name = "authfs_fd_server";
+    get_interface(&service_name).map_err(|e| {
+        io::Error::new(
+            io::ErrorKind::AddrNotAvailable,
+            format!("Cannot reach authfs_fd_server binder service: {}", e),
+        )
+    })
+}
+
+fn get_rpc_binder(cid: u32) -> io::Result<VirtFdService> {
+    // SAFETY: AIBinder returned by RpcClient has correct reference count, and the ownership can be
+    // safely taken by new_spibinder.
+    let ibinder = unsafe {
+        new_spibinder(binder_rpc_unstable_bindgen::RpcClient(cid, RPC_SERVICE_PORT) as *mut AIBinder)
+    };
+    if let Some(ibinder) = ibinder {
+        Ok(IVirtFdService::try_from(ibinder).map_err(|e| {
+            io::Error::new(
+                io::ErrorKind::AddrNotAvailable,
+                format!("Cannot connect to RPC service: {}", e),
+            )
+        })?)
+    } else {
+        Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid raw AIBinder"))
+    }
+}
+
+pub fn get_binder_service(cid: Option<u32>) -> io::Result<VirtFdService> {
+    if let Some(cid) = cid {
+        get_rpc_binder(cid)
+    } else {
+        get_local_binder()
+    }
+}
+
 /// A trait for reading data by chunks. Chunks can be read by specifying the chunk index. Only the
 /// last chunk may have incomplete chunk size.
 pub trait ReadByChunk {
diff --git a/authfs/src/file/remote_file.rs b/authfs/src/file/remote_file.rs
index bd99893..0b6c007 100644
--- a/authfs/src/file/remote_file.rs
+++ b/authfs/src/file/remote_file.rs
@@ -19,14 +19,9 @@
 use std::io;
 use std::sync::{Arc, Mutex};
 
-use super::{ChunkBuffer, RandomWrite, ReadByChunk};
+use super::{ChunkBuffer, RandomWrite, ReadByChunk, VirtFdService};
 use crate::common::CHUNK_SIZE;
 
-use authfs_aidl_interface::aidl::com::android::virt::fs::IVirtFdService;
-use authfs_aidl_interface::binder::Strong;
-
-type VirtFdService = Strong<dyn IVirtFdService::IVirtFdService>;
-
 fn remote_read_chunk(
     service: &Arc<Mutex<VirtFdService>>,
     remote_fd: i32,
diff --git a/authfs/src/main.rs b/authfs/src/main.rs
index b30195a..593fa74 100644
--- a/authfs/src/main.rs
+++ b/authfs/src/main.rs
@@ -53,6 +53,10 @@
     #[structopt(parse(from_os_str))]
     mount_point: PathBuf,
 
+    /// CID of the VM where the service runs.
+    #[structopt(long)]
+    cid: Option<u32>,
+
     /// A read-only remote file with integrity check. Can be multiple.
     ///
     /// For example, `--remote-verified-file 5:10:1234:/path/to/cert` tells the filesystem to
@@ -205,8 +209,11 @@
     })
 }
 
-fn new_config_remote_verified_file(remote_id: i32, file_size: u64) -> Result<FileConfig> {
-    let service = file::get_local_binder();
+fn new_config_remote_verified_file(
+    service: file::VirtFdService,
+    remote_id: i32,
+    file_size: u64,
+) -> Result<FileConfig> {
     let signature = service.readFsveritySignature(remote_id).context("Failed to read signature")?;
 
     let service = Arc::new(Mutex::new(service));
@@ -223,8 +230,12 @@
     })
 }
 
-fn new_config_remote_unverified_file(remote_id: i32, file_size: u64) -> Result<FileConfig> {
-    let reader = RemoteFileReader::new(Arc::new(Mutex::new(file::get_local_binder())), remote_id);
+fn new_config_remote_unverified_file(
+    service: file::VirtFdService,
+    remote_id: i32,
+    file_size: u64,
+) -> Result<FileConfig> {
+    let reader = RemoteFileReader::new(Arc::new(Mutex::new(service)), remote_id);
     Ok(FileConfig::RemoteUnverifiedReadonlyFile { reader, file_size })
 }
 
@@ -251,31 +262,38 @@
     Ok(FileConfig::LocalUnverifiedReadonlyFile { reader, file_size })
 }
 
-fn new_config_remote_new_verified_file(remote_id: i32) -> Result<FileConfig> {
-    let remote_file =
-        RemoteFileEditor::new(Arc::new(Mutex::new(file::get_local_binder())), remote_id);
+fn new_config_remote_new_verified_file(
+    service: file::VirtFdService,
+    remote_id: i32,
+) -> Result<FileConfig> {
+    let remote_file = RemoteFileEditor::new(Arc::new(Mutex::new(service)), remote_id);
     Ok(FileConfig::RemoteVerifiedNewFile { editor: VerifiedFileEditor::new(remote_file) })
 }
 
 fn prepare_file_pool(args: &Args) -> Result<BTreeMap<Inode, FileConfig>> {
     let mut file_pool = BTreeMap::new();
 
+    let service = file::get_binder_service(args.cid)?;
+
     for config in &args.remote_ro_file {
         file_pool.insert(
             config.ino,
-            new_config_remote_verified_file(config.remote_id, config.file_size)?,
+            new_config_remote_verified_file(service.clone(), config.remote_id, config.file_size)?,
         );
     }
 
     for config in &args.remote_ro_file_unverified {
         file_pool.insert(
             config.ino,
-            new_config_remote_unverified_file(config.remote_id, config.file_size)?,
+            new_config_remote_unverified_file(service.clone(), config.remote_id, config.file_size)?,
         );
     }
 
     for config in &args.remote_new_rw_file {
-        file_pool.insert(config.ino, new_config_remote_new_verified_file(config.remote_id)?);
+        file_pool.insert(
+            config.ino,
+            new_config_remote_new_verified_file(service.clone(), config.remote_id)?,
+        );
     }
 
     for config in &args.local_ro_file {
diff --git a/compos/Android.bp b/compos/Android.bp
index fc0517f..858f64c 100644
--- a/compos/Android.bp
+++ b/compos/Android.bp
@@ -8,6 +8,8 @@
     rustlibs: [
         "compos_aidl_interface-rust",
         "libanyhow",
+        "libbinder_rpc_unstable_bindgen",
+        "libbinder_rs",
         "libclap",
         "liblibc",
         "liblog_rust",
@@ -16,6 +18,9 @@
         "libscopeguard",
     ],
     prefer_rlib: true,
+    shared_libs: [
+        "libbinder_rpc_unstable",
+    ],
     apex_available: [
         "com.android.compos",
     ],
@@ -28,11 +33,16 @@
         "compos_aidl_interface-rust",
         "libandroid_logger",
         "libanyhow",
+        "libbinder_rpc_unstable_bindgen",
+        "libbinder_rs",
         "libclap",
         "liblog_rust",
         "libminijail_rust",
     ],
     prefer_rlib: true,
+    shared_libs: [
+        "libbinder_rpc_unstable",
+    ],
     apex_available: [
         "com.android.compos",
     ],
@@ -55,3 +65,10 @@
         "com.android.compos",
     ],
 }
+
+// TODO(b/190503456) Remove this when vm/virtualizationservice generates payload.img from vm_config
+prebuilt_etc {
+    name: "compos_payload_config",
+    src: "payload_config.json",
+    filename: "payload_config.json",
+}
diff --git a/compos/apex/Android.bp b/compos/apex/Android.bp
index 7ced384..3a8f601 100644
--- a/compos/apex/Android.bp
+++ b/compos/apex/Android.bp
@@ -40,4 +40,12 @@
         "compsvc_worker",
         "pvm_exec",
     ],
+
+    apps: [
+        "CompOSPayloadApp",
+    ],
+
+    prebuilts: [
+        "compos_payload_config",
+    ],
 }
diff --git a/compos/apk/Android.bp b/compos/apk/Android.bp
new file mode 100644
index 0000000..c6192b9
--- /dev/null
+++ b/compos/apk/Android.bp
@@ -0,0 +1,9 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_app {
+    name: "CompOSPayloadApp",
+    sdk_version: "current",
+    apex_available: ["com.android.compos"],
+}
diff --git a/compos/apk/AndroidManifest.xml b/compos/apk/AndroidManifest.xml
new file mode 100644
index 0000000..1e9352b
--- /dev/null
+++ b/compos/apk/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="com.android.compos.payload">
+    <application android:label="CompOS" />
+</manifest>
diff --git a/compos/apk/assets/vm_config.json b/compos/apk/assets/vm_config.json
new file mode 100644
index 0000000..a8dca71
--- /dev/null
+++ b/compos/apk/assets/vm_config.json
@@ -0,0 +1,34 @@
+{
+  "version": 1,
+  "os": {
+    "name": "microdroid"
+  },
+  "task": {
+    "type": "executable",
+    "command": "/apex/com.android.compos/bin/compsvc",
+    "args": [
+      "--rpc-binder",
+      "/apex/com.android.art/bin/dex2oat64"
+    ]
+  },
+  "apexes": [
+    {
+      "name": "com.android.adbd"
+    },
+    {
+      "name": "com.android.art"
+    },
+    {
+      "name": "com.android.compos"
+    },
+    {
+      "name": "com.android.i18n"
+    },
+    {
+      "name": "com.android.os.statsd"
+    },
+    {
+      "name": "com.android.sdkext"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/compos/payload_config.json b/compos/payload_config.json
new file mode 100644
index 0000000..588ccca
--- /dev/null
+++ b/compos/payload_config.json
@@ -0,0 +1,15 @@
+{
+  "apk": {
+    "path": "/apex/com.android.compos/app/CompOSPayloadApp/CompOSPayloadApp.apk",
+    "name": "com.android.compos.payload"
+  },
+  "system_apexes": [
+    "com.android.adbd",
+    "com.android.art",
+    "com.android.compos",
+    "com.android.i18n",
+    "com.android.os.statsd",
+    "com.android.sdkext"
+  ],
+  "payload_config_path": "/mnt/apk/assets/vm_config.json"
+}
\ No newline at end of file
diff --git a/compos/src/common.rs b/compos/src/common.rs
new file mode 100644
index 0000000..6cad63a
--- /dev/null
+++ b/compos/src/common.rs
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 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.
+ */
+
+/// Port to listen. This should be out of future port range (if happens) that microdroid may
+/// reserve for system components.
+pub const VSOCK_PORT: u32 = 6432;
+
+/// Service name of local binder. Used only for debugging purpose.
+pub const SERVICE_NAME: &str = "compsvc";
diff --git a/compos/src/compsvc.rs b/compos/src/compsvc.rs
index ddfcea0..4ad2e03 100644
--- a/compos/src/compsvc.rs
+++ b/compos/src/compsvc.rs
@@ -29,7 +29,8 @@
 //!     - actual task
 
 use anyhow::{bail, Context, Result};
-use log::error;
+use binder::unstable_api::AsNative;
+use log::{debug, error};
 use minijail::{self, Minijail};
 use std::path::PathBuf;
 
@@ -42,14 +43,17 @@
     StatusCode, Strong,
 };
 
-const SERVICE_NAME: &str = "compsvc";
+mod common;
+use common::{SERVICE_NAME, VSOCK_PORT};
+
 const WORKER_BIN: &str = "/apex/com.android.compos/bin/compsvc_worker";
 // TODO: Replace with a valid directory setup in the VM.
-const AUTHFS_MOUNTPOINT: &str = "/data/local/tmp/authfs_mnt";
+const AUTHFS_MOUNTPOINT: &str = "/data/local/tmp";
 
 struct CompService {
     worker_bin: PathBuf,
     task_bin: String,
+    rpc_binder: bool,
     debuggable: bool,
 }
 
@@ -128,11 +132,14 @@
              .long("debug"))
         .arg(clap::Arg::with_name("task_bin")
              .required(true))
+        .arg(clap::Arg::with_name("rpc_binder")
+             .long("rpc-binder"))
         .get_matches();
 
     Ok(CompService {
         task_bin: matches.value_of("task_bin").unwrap().to_string(),
         worker_bin: PathBuf::from(WORKER_BIN),
+        rpc_binder: matches.is_present("rpc_binder"),
         debuggable: matches.is_present("debug"),
     })
 }
@@ -144,10 +151,29 @@
 
     let service = parse_args()?;
 
-    ProcessState::start_thread_pool();
-    // TODO: switch to remote binder
-    add_service(SERVICE_NAME, CompService::new_binder(service).as_binder())
-        .with_context(|| format!("Failed to register service {}", SERVICE_NAME))?;
-    ProcessState::join_thread_pool();
-    bail!("Unexpected exit after join_thread_pool")
+    if service.rpc_binder {
+        let mut service = CompService::new_binder(service).as_binder();
+        debug!("compsvc is starting as a rpc service.");
+        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+        // Plus the binder objects are threadsafe.
+        let retval = unsafe {
+            binder_rpc_unstable_bindgen::RunRpcServer(
+                service.as_native_mut() as *mut binder_rpc_unstable_bindgen::AIBinder,
+                VSOCK_PORT,
+            )
+        };
+        if retval {
+            debug!("RPC server has shut down gracefully");
+            Ok(())
+        } else {
+            bail!("Premature termination of RPC server");
+        }
+    } else {
+        ProcessState::start_thread_pool();
+        debug!("compsvc is starting as a local service.");
+        add_service(SERVICE_NAME, CompService::new_binder(service).as_binder())
+            .with_context(|| format!("Failed to register service {}", SERVICE_NAME))?;
+        ProcessState::join_thread_pool();
+        bail!("Unexpected exit after join_thread_pool")
+    }
 }
diff --git a/compos/src/compsvc_worker.rs b/compos/src/compsvc_worker.rs
index cf40f81..0456d58 100644
--- a/compos/src/compsvc_worker.rs
+++ b/compos/src/compsvc_worker.rs
@@ -30,7 +30,7 @@
 use std::thread::sleep;
 use std::time::{Duration, Instant};
 
-const AUTHFS_BIN: &str = "/apex/com.android.virt/bin/authfs";
+const AUTHFS_BIN: &str = "/system/bin/authfs";
 const AUTHFS_SETUP_POLL_INTERVAL_MS: Duration = Duration::from_millis(50);
 const AUTHFS_SETUP_TIMEOUT_SEC: Duration = Duration::from_secs(10);
 const FUSE_SUPER_MAGIC: FsType = FsType(0x65735546);
@@ -47,7 +47,11 @@
     // TODO(b/185175567): Run in a more restricted sandbox.
     let jail = Minijail::new()?;
 
-    let mut args = vec![AUTHFS_BIN.to_string(), config.authfs_root.clone()];
+    let mut args = vec![
+        AUTHFS_BIN.to_string(),
+        config.authfs_root.clone(),
+        "--cid=2".to_string(), // Always use host unless we need to support other cases
+    ];
     for conf in &config.in_fds {
         // TODO(b/185178698): Many input files need to be signed and verified.
         // or can we use debug cert for now, which is better than nothing?
diff --git a/compos/src/pvm_exec.rs b/compos/src/pvm_exec.rs
index fcde266..987a198 100644
--- a/compos/src/pvm_exec.rs
+++ b/compos/src/pvm_exec.rs
@@ -25,6 +25,8 @@
 //! used. It is only for ergonomics.
 
 use anyhow::{bail, Context, Result};
+use binder::unstable_api::{new_spibinder, AIBinder};
+use binder::FromIBinder;
 use log::{error, warn};
 use minijail::Minijail;
 use nix::fcntl::{fcntl, FcntlArg::F_GETFD};
@@ -39,11 +41,26 @@
 };
 use compos_aidl_interface::binder::Strong;
 
-static SERVICE_NAME: &str = "compsvc";
-static FD_SERVER_BIN: &str = "/apex/com.android.virt/bin/fd_server";
+mod common;
+use common::{SERVICE_NAME, VSOCK_PORT};
 
-fn get_local_service() -> Strong<dyn ICompService> {
-    compos_aidl_interface::binder::get_interface(SERVICE_NAME).expect("Cannot reach compsvc")
+const FD_SERVER_BIN: &str = "/apex/com.android.virt/bin/fd_server";
+
+fn get_local_service() -> Result<Strong<dyn ICompService>> {
+    compos_aidl_interface::binder::get_interface(SERVICE_NAME).context("get local binder")
+}
+
+fn get_rpc_binder(cid: u32) -> Result<Strong<dyn ICompService>> {
+    // SAFETY: AIBinder returned by RpcClient has correct reference count, and the ownership can be
+    // safely taken by new_spibinder.
+    let ibinder = unsafe {
+        new_spibinder(binder_rpc_unstable_bindgen::RpcClient(cid, VSOCK_PORT) as *mut AIBinder)
+    };
+    if let Some(ibinder) = ibinder {
+        ICompService::try_from(ibinder).context("Cannot connect to RPC service")
+    } else {
+        bail!("Invalid raw AIBinder")
+    }
 }
 
 fn spawn_fd_server(metadata: &Metadata, debuggable: bool) -> Result<Minijail> {
@@ -53,7 +70,7 @@
         vec![]
     };
 
-    let mut args = vec![FD_SERVER_BIN.to_string()];
+    let mut args = vec![FD_SERVER_BIN.to_string(), "--rpc-binder".to_string()];
     for metadata in &metadata.input_fd_annotations {
         args.push("--ro-fds".to_string());
         args.push(metadata.fd.to_string());
@@ -86,6 +103,7 @@
 struct Config {
     args: Vec<String>,
     metadata: Metadata,
+    cid: Option<u32>,
     debuggable: bool,
 }
 
@@ -102,6 +120,9 @@
              .takes_value(true)
              .multiple(true)
              .use_delimiter(true))
+        .arg(clap::Arg::with_name("cid")
+             .takes_value(true)
+             .long("cid"))
         .arg(clap::Arg::with_name("debug")
              .long("debug"))
         .arg(clap::Arg::with_name("args")
@@ -132,18 +153,21 @@
     let output_fd_annotations = results?;
 
     let args: Vec<_> = matches.values_of("args").unwrap().map(|s| s.to_string()).collect();
+    let cid =
+        if let Some(arg) = matches.value_of("cid") { Some(arg.parse::<u32>()?) } else { None };
     let debuggable = matches.is_present("debug");
 
     Ok(Config {
         args,
         metadata: Metadata { input_fd_annotations, output_fd_annotations },
+        cid,
         debuggable,
     })
 }
 
 fn main() -> Result<()> {
     // 1. Parse the command line arguments for collect execution data.
-    let Config { args, metadata, debuggable } = parse_args()?;
+    let Config { args, metadata, cid, debuggable } = parse_args()?;
 
     // 2. Spawn and configure a fd_server to serve remote read/write requests.
     let fd_server_jail = spawn_fd_server(&metadata, debuggable)?;
@@ -156,7 +180,8 @@
     });
 
     // 3. Send the command line args to the remote to execute.
-    let exit_code = get_local_service().execute(&args, &metadata).context("Binder call failed")?;
+    let service = if let Some(cid) = cid { get_rpc_binder(cid) } else { get_local_service() }?;
+    let exit_code = service.execute(&args, &metadata).context("Binder call failed")?;
 
     // Be explicit about the lifetime, which should last at least until the task is finished.
     drop(fd_server_lifetime);
diff --git a/microdroid/Android.bp b/microdroid/Android.bp
index 146d4ff..41ee0d2 100644
--- a/microdroid/Android.bp
+++ b/microdroid/Android.bp
@@ -49,6 +49,7 @@
         "microdroid_init_rc",
         "microdroid_launcher",
         "microdroid_manager",
+
         "ueventd.rc",
         "libbinder",
         "libbinder_ndk",
@@ -73,7 +74,6 @@
         "linkerconfig",
         "servicemanager",
         "tombstoned",
-        "wait_for_keymaster",
         "cgroups.json",
         "public.libraries.android.txt",
 
@@ -99,7 +99,12 @@
         },
         lib64: {
             deps: [
+                "apkdmverity",
+                "authfs",
                 "zipfuse",
+
+                // TODO(b/184872979): Needed by authfs. Remove once the Rust API is created.
+                "libbinder_rpc_unstable",
             ],
         },
     },
@@ -396,11 +401,6 @@
 }
 
 prebuilt_etc {
-    name: "microdroid_payload.json",
-    src: "microdroid_payload.json",
-}
-
-prebuilt_etc {
     name: "microdroid_vendor_manifest",
     src: "microdroid_vendor_manifest.xml",
     filename: "manifest.xml",
diff --git a/microdroid/README.md b/microdroid/README.md
index 6b9f4b1..aae6e66 100644
--- a/microdroid/README.md
+++ b/microdroid/README.md
@@ -42,51 +42,33 @@
 
 ## Running
 
-Create a config file, `microdroid.json`:
+Create two config files, `microdroid.json` and `payload.json`:
 
 ```json
+microdroid.json:
+
 {
   "bootloader": "/apex/com.android.virt/etc/microdroid_bootloader",
   "disks": [
     {
       "partitions": [
         {
-          "label": "misc",
-          "path": "/data/local/tmp/microdroid/misc.img"
-        },
-        {
           "label": "boot_a",
           "path": "/apex/com.android.virt/etc/fs/microdroid_boot-5.10.img"
         },
         {
-          "label": "boot_b",
-          "path": "/apex/com.android.virt/etc/fs/microdroid_boot-5.10.img"
-        },
-        {
           "label": "vendor_boot_a",
           "path": "/apex/com.android.virt/etc/fs/microdroid_vendor_boot-5.10.img"
         },
         {
-          "label": "vendor_boot_b",
-          "path": "/apex/com.android.virt/etc/fs/microdroid_vendor_boot-5.10.img"
-        },
-        {
           "label": "vbmeta_a",
           "path": "/apex/com.android.virt/etc/fs/microdroid_vbmeta.img"
         },
         {
-          "label": "vbmeta_b",
-          "path": "/apex/com.android.virt/etc/fs/microdroid_vbmeta.img"
-        },
-        {
           "label": "vbmeta_system_a",
           "path": "/apex/com.android.virt/etc/fs/microdroid_vbmeta_system.img"
         },
         {
-          "label": "vbmeta_system_b",
-          "path": "/apex/com.android.virt/etc/fs/microdroid_vbmeta_system.img"
-        },
-        {
           "label": "super",
           "path": "/apex/com.android.virt/etc/fs/microdroid_super.img"
         }
@@ -108,9 +90,20 @@
     }
   ]
 }
+
+payload.json:
+
+{
+  "system_apexes" : [
+    "com.android.adbd",
+    "com.android.i18n",
+    "com.android.os.statsd",
+    "com.android.sdkext"
+  ]
+}
 ```
 
-Copy the artifacts to the temp directory, create the composite image using
+Copy the these files to the temp directory, create the composite image using
 `mk_cdisk` and copy the VM config file. For now, some other files have to be
 manually created. In the future, you won't need these, and this shall be done
 via [`virtualizationservice`](../virtualizationservice/).
@@ -118,8 +111,8 @@
 ```sh
 $ adb root
 $ adb shell 'mkdir /data/local/tmp/microdroid'
-$ adb shell 'dd if=/dev/zero of=/data/local/tmp/microdroid/misc.img bs=4k count=256'
-$ adb shell 'cd /data/local/tmp/microdroid; /apex/com.android.virt/bin/mk_payload /apex/com.android.virt/etc/microdroid_payload.json payload.img'
+$ adb push payload.json /data/local/tmp/microdroid/payload.json
+$ adb shell 'cd /data/local/tmp/microdroid; /apex/com.android.virt/bin/mk_payload payload.json payload.img'
 $ adb shell 'chmod go+r /data/local/tmp/microdroid/payload*'
 $ adb push microdroid.json /data/local/tmp/microdroid/microdroid.json
 ```
diff --git a/microdroid/init.rc b/microdroid/init.rc
index 2385d8f..4410b82 100644
--- a/microdroid/init.rc
+++ b/microdroid/init.rc
@@ -22,6 +22,8 @@
 
     start ueventd
 
+    # TODO(b/190343842) verify apexes/apk before mounting them.
+
     # Exec apexd in the VM mode to avoid unnecessary overhead of normal mode.
     # (e.g. session management)
     exec - root system -- /system/bin/apexd --vm
@@ -29,6 +31,7 @@
     perform_apex_config
     exec_start derive_sdk
 
+    exec - root system -- /system/bin/apkdmverity /dev/block/by-name/microdroid-apk /dev/block/by-name/microdroid-apk-idsig microdroid-apk
     mkdir /mnt/apk 0755 system system
     start zipfuse
 
@@ -87,15 +90,6 @@
     # Load persist properties and override properties (if enabled) from /data.
     trigger load_persist_props_action
 
-    # Should be before netd, but after apex, properties and logging is available.
-    trigger load_bpf_programs
-
-    # Now we can start zygote for devices with file based encryption
-    trigger zygote-start
-
-    # Remove a file to wake up anything waiting for firmware.
-    trigger firmware_mounts_complete
-
     trigger early-boot
     trigger boot
 
@@ -109,8 +103,6 @@
 on late-fs
     start vendor.keymint-default
 
-    exec_start wait_for_keymaster
-
     # TODO(b/185767624): change the hard-coded size?
     mount tmpfs tmpfs /data noatime nosuid nodev rw size=128M
 
diff --git a/microdroid/microdroid_cdisk.json b/microdroid/microdroid_cdisk.json
index 5721775..d0a5025 100644
--- a/microdroid/microdroid_cdisk.json
+++ b/microdroid/microdroid_cdisk.json
@@ -1,44 +1,24 @@
 {
   "partitions": [
     {
-      "label": "misc",
-      "path": "misc.img"
-    },
-    {
       "label": "boot_a",
-      "path": "microdroid_boot-5.10.img"
-    },
-    {
-      "label": "boot_b",
-      "path": "microdroid_boot-5.10.img"
+      "path": "/apex/com.android.virt/etc/fs/microdroid_boot-5.10.img"
     },
     {
       "label": "vendor_boot_a",
-      "path": "microdroid_vendor_boot-5.10.img"
-    },
-    {
-      "label": "vendor_boot_b",
-      "path": "microdroid_vendor_boot-5.10.img"
+      "path": "/apex/com.android.virt/etc/fs/microdroid_vendor_boot-5.10.img"
     },
     {
       "label": "vbmeta_a",
-      "path": "microdroid_vbmeta.img"
-    },
-    {
-      "label": "vbmeta_b",
-      "path": "microdroid_vbmeta.img"
+      "path": "/apex/com.android.virt/etc/fs/microdroid_vbmeta.img"
     },
     {
       "label": "vbmeta_system_a",
-      "path": "microdroid_vbmeta_system.img"
-    },
-    {
-      "label": "vbmeta_system_b",
-      "path": "microdroid_vbmeta_system.img"
+      "path": "/apex/com.android.virt/etc/fs/microdroid_vbmeta_system.img"
     },
     {
       "label": "super",
-      "path": "microdroid_super.img"
+      "path": "/apex/com.android.virt/etc/fs/microdroid_super.img"
     }
   ]
 }
diff --git a/microdroid/microdroid_cdisk_env.json b/microdroid/microdroid_cdisk_env.json
index b0fbe44..8c84ed5 100644
--- a/microdroid/microdroid_cdisk_env.json
+++ b/microdroid/microdroid_cdisk_env.json
@@ -2,7 +2,7 @@
   "partitions": [
     {
       "label": "uboot_env",
-      "path": "uboot_env.img"
+      "path": "/apex/com.android.virt/etc/uboot_env.img"
     }
   ]
 }
diff --git a/microdroid/microdroid_payload.json b/microdroid/microdroid_payload.json
deleted file mode 100644
index 7af0452..0000000
--- a/microdroid/microdroid_payload.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-  "system_apexes": [
-    "com.android.adbd",
-    "com.android.i18n",
-    "com.android.os.statsd",
-    "com.android.sdkext"
-  ],
-  "apk": {
-    "name": "com.android.microdroid.test",
-    "path": "/apex/com.android.virt/app/MicrodroidTestApp/MicrodroidTestApp.apk"
-  },
-  "payload_config_path": "/mnt/apk/assets/vm_config.json"
-}
diff --git a/microdroid/payload/mk_payload.cc b/microdroid/payload/mk_payload.cc
index 1da71de..c31dcff 100644
--- a/microdroid/payload/mk_payload.cc
+++ b/microdroid/payload/mk_payload.cc
@@ -87,8 +87,9 @@
 
 struct ApkConfig {
     std::string name;
-    // TODO(jooyung): find path/idsig with name
     std::string path;
+    // TODO(jooyung) make this required?
+    std::optional<std::string> idsig_path;
 };
 
 struct Config {
@@ -144,6 +145,7 @@
 Result<void> ParseJson(const Json::Value& value, ApkConfig& apk_config) {
     DO(ParseJson(value["name"], apk_config.name));
     DO(ParseJson(value["path"], apk_config.path));
+    DO(ParseJson(value["idsig_path"], apk_config.idsig_path));
     return {};
 }
 
@@ -226,7 +228,9 @@
         auto* apk = metadata.mutable_apk();
         apk->set_name(config.apk->name);
         apk->set_payload_partition_name("microdroid-apk");
-        // TODO(jooyung): set idsig partition as well
+        if (config.apk->idsig_path.has_value()) {
+            apk->set_idsig_partition_name("microdroid-apk-idsig");
+        }
     }
 
     if (config.payload_config_path.has_value()) {
@@ -237,7 +241,9 @@
     return WriteMetadata(metadata, out);
 }
 
-Result<void> GenerateFiller(const std::string& file_path, const std::string& filler_path) {
+// fill (zeros + original file's size) with aligning BLOCK_SIZE(4096) boundary
+// return true when the filler is generated.
+Result<bool> SizeFiller(const std::string& file_path, const std::string& filler_path) {
     auto file_size = GetFileSize(file_path);
     if (!file_size.ok()) {
         return file_size.error();
@@ -258,7 +264,36 @@
     if (write(fd.get(), &size, sizeof(size)) <= 0) {
         return ErrnoError() << "write(" << filler_path << ") failed.";
     }
-    return {};
+    return true;
+}
+
+// fill zeros to align |file_path|'s size to BLOCK_SIZE(4096) boundary.
+// return true when the filler is generated.
+Result<bool> ZeroFiller(const std::string& file_path, const std::string& filler_path) {
+    auto file_size = GetFileSize(file_path);
+    if (!file_size.ok()) {
+        return file_size.error();
+    }
+    auto disk_size = AlignToPartitionSize(*file_size);
+    if (disk_size <= *file_size) {
+        return false;
+    }
+    unique_fd fd(TEMP_FAILURE_RETRY(open(filler_path.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0600)));
+    if (fd.get() == -1) {
+        return ErrnoError() << "open(" << filler_path << ") failed.";
+    }
+    if (ftruncate(fd.get(), disk_size - *file_size) == -1) {
+        return ErrnoError() << "ftruncate(" << filler_path << ") failed.";
+    }
+    return true;
+}
+
+// Do not generate any fillers
+// Note that CreateCompositeDisk() handles gaps between partitions.
+Result<bool> NoFiller(const std::string& file_path, const std::string& filler_path) {
+    (void)file_path;
+    (void)filler_path;
+    return false;
 }
 
 Result<void> MakePayload(const Config& config, const std::string& metadata_file,
@@ -274,14 +309,18 @@
     });
 
     int filler_count = 0;
-    auto add_partition = [&](auto partition_name, auto file_path) -> Result<void> {
+    auto add_partition = [&](auto partition_name, auto file_path, auto filler) -> Result<void> {
+        std::vector<std::string> image_files{file_path};
+
         std::string filler_path = output_file + "." + std::to_string(filler_count++);
-        if (auto ret = GenerateFiller(file_path, filler_path); !ret.ok()) {
+        if (auto ret = filler(file_path, filler_path); !ret.ok()) {
             return ret.error();
+        } else if (*ret) {
+            image_files.push_back(filler_path);
         }
         partitions.push_back(MultipleImagePartition{
                 .label = partition_name,
-                .image_file_paths = {file_path, filler_path},
+                .image_file_paths = image_files,
                 .type = kLinuxFilesystem,
                 .read_only = true,
         });
@@ -292,18 +331,24 @@
     for (size_t i = 0; i < config.apexes.size(); i++) {
         const auto& apex_config = config.apexes[i];
         std::string apex_path = ToAbsolute(apex_config.path, config.dirname);
-        if (auto ret = add_partition("microdroid-apex-" + std::to_string(i), apex_path);
+        if (auto ret = add_partition("microdroid-apex-" + std::to_string(i), apex_path, SizeFiller);
             !ret.ok()) {
             return ret.error();
         }
     }
-    // put apk with "size" filler if necessary.
+    // put apk with "zero" filler.
     // TODO(jooyung): partition name("microdroid-apk") is TBD
     if (config.apk.has_value()) {
         std::string apk_path = ToAbsolute(config.apk->path, config.dirname);
-        if (auto ret = add_partition("microdroid-apk", apk_path); !ret.ok()) {
+        if (auto ret = add_partition("microdroid-apk", apk_path, ZeroFiller); !ret.ok()) {
             return ret.error();
         }
+        if (config.apk->idsig_path.has_value()) {
+            std::string idsig_path = ToAbsolute(config.apk->idsig_path.value(), config.dirname);
+            if (auto ret = add_partition("microdroid-apk-idsig", idsig_path, NoFiller); !ret.ok()) {
+                return ret.error();
+            }
+        }
     }
 
     const std::string gpt_header = AppendFileName(output_file, "-header");
diff --git a/microdroid/sepolicy/Android.bp b/microdroid/sepolicy/Android.bp
index 9bb6408..6488153 100644
--- a/microdroid/sepolicy/Android.bp
+++ b/microdroid/sepolicy/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "packages_modules_Virtualization_license"
+    // to get the below license kinds:
+    //   legacy_unencumbered
+    default_applicable_licenses: ["packages_modules_Virtualization_license"],
+}
+
 system_policy_files = [
     "system/private/security_classes",
     "system/private/initial_sids",
diff --git a/microdroid/sepolicy/system/private/apkdmverity.te b/microdroid/sepolicy/system/private/apkdmverity.te
new file mode 100644
index 0000000..c6160be
--- /dev/null
+++ b/microdroid/sepolicy/system/private/apkdmverity.te
@@ -0,0 +1,29 @@
+# apkdmverity is a program that protects a signed APK file using dm-verity.
+
+type apkdmverity, domain, coredomain;
+type apkdmverity_exec, exec_type, file_type, system_file_type;
+
+# allow domain transition from init
+init_daemon_domain(apkdmverity)
+
+# apkdmverity accesses /dev/block/by-name/metadata which points to
+# a /dev/vd* block device file.
+allow apkdmverity block_device:dir r_dir_perms;
+allow apkdmverity block_device:lnk_file r_file_perms;
+allow apkdmverity vd_device:blk_file r_file_perms;
+
+# allow apkdmverity to create dm-verity devices
+allow apkdmverity dm_device:{chr_file blk_file} rw_file_perms;
+# sys_admin is required to access the device-mapper and mount
+allow apkdmverity self:global_capability_class_set sys_admin;
+
+# allow apkdmverity to create loop devices with /dev/loop-control
+allow apkdmverity loop_control_device:chr_file rw_file_perms;
+
+# allow apkdmverity to access loop devices
+allow apkdmverity loop_device:blk_file rw_file_perms;
+allowxperm apkdmverity loop_device:blk_file ioctl {
+  LOOP_SET_STATUS64
+  LOOP_SET_FD
+  LOOP_SET_DIRECT_IO
+};
diff --git a/microdroid/sepolicy/system/private/domain.te b/microdroid/sepolicy/system/private/domain.te
index c451fcf..4a59f73 100644
--- a/microdroid/sepolicy/system/private/domain.te
+++ b/microdroid/sepolicy/system/private/domain.te
@@ -501,7 +501,8 @@
 
 # Only init and otapreopt_chroot should be mounting filesystems on locations
 # labeled system or vendor (/product and /vendor respectively).
-neverallow { domain -init -otapreopt_chroot } { system_file_type vendor_file_type }:dir_file_class_set mounton;
+# In microdroid, zipfuse is allowed mounton /mnt/apk.
+neverallow { domain -init -otapreopt_chroot -zipfuse } { system_file_type vendor_file_type }:dir_file_class_set mounton;
 
 # Only allow init and vendor_init to read/write mm_events properties
 # NOTE: dumpstate is allowed to read any system property
diff --git a/microdroid/sepolicy/system/private/file_contexts b/microdroid/sepolicy/system/private/file_contexts
index 3c75e81..c4b4b2c 100644
--- a/microdroid/sepolicy/system/private/file_contexts
+++ b/microdroid/sepolicy/system/private/file_contexts
@@ -364,7 +364,6 @@
 /system/bin/stats                u:object_r:stats_exec:s0
 /system/bin/statsd               u:object_r:statsd_exec:s0
 /system/bin/bpfloader            u:object_r:bpfloader_exec:s0
-/system/bin/wait_for_keymaster   u:object_r:wait_for_keymaster_exec:s0
 /system/bin/watchdogd            u:object_r:watchdogd_exec:s0
 /system/bin/apexd                u:object_r:apexd_exec:s0
 /system/bin/gsid                 u:object_r:gsid_exec:s0
@@ -377,6 +376,7 @@
 /system/bin/zipfuse              u:object_r:zipfuse_exec:s0
 /system/bin/microdroid_launcher  u:object_r:microdroid_launcher_exec:s0
 /system/bin/microdroid_manager   u:object_r:microdroid_manager_exec:s0
+/system/bin/apkdmverity          u:object_r:apkdmverity_exec:s0
 
 #############################
 # Vendor files
diff --git a/microdroid/sepolicy/system/private/kernel.te b/microdroid/sepolicy/system/private/kernel.te
index 5341163..2d49445 100644
--- a/microdroid/sepolicy/system/private/kernel.te
+++ b/microdroid/sepolicy/system/private/kernel.te
@@ -28,6 +28,12 @@
 allow kernel null_device:chr_file relabelto;
 allow kernel random_device:chr_file relabelto;
 allow kernel snapuserd_exec:file relabelto;
+allow kernel vd_device:blk_file read;
 
 allow kernel kmsg_device:chr_file write;
 allow kernel gsid:fd use;
+
+# apkdmverity attaches a loop device to idsig file
+# and the loop device is used by zipfuse later.
+# This requires kernel to use the fd opened by apkdmverity.
+allow kernel apkdmverity:fd use;
diff --git a/microdroid/sepolicy/system/private/keystore.te b/microdroid/sepolicy/system/private/keystore.te
index 3fccf59..0e57045 100644
--- a/microdroid/sepolicy/system/private/keystore.te
+++ b/microdroid/sepolicy/system/private/keystore.te
@@ -29,7 +29,6 @@
 
 get_prop(keystore, keystore_listen_prop)
 
-# Keystore needs to transfer binder references to vold and wait_for_keymaster so that they
+# Keystore needs to transfer binder references to vold so that it
 # can call keystore methods on those references.
 allow keystore vold:binder transfer;
-allow keystore wait_for_keymaster:binder transfer;
diff --git a/microdroid/sepolicy/system/private/microdroid_launcher.te b/microdroid/sepolicy/system/private/microdroid_launcher.te
index e68b687..5a313b6 100644
--- a/microdroid/sepolicy/system/private/microdroid_launcher.te
+++ b/microdroid/sepolicy/system/private/microdroid_launcher.te
@@ -21,3 +21,6 @@
 
 # Allow to use terminal
 allow microdroid_launcher devpts:chr_file rw_file_perms;
+
+# Allow to set debug prop
+set_prop(microdroid_launcher, debug_prop)
diff --git a/microdroid/sepolicy/system/private/microdroid_manager.te b/microdroid/sepolicy/system/private/microdroid_manager.te
index f2feca2..deb969c 100644
--- a/microdroid/sepolicy/system/private/microdroid_manager.te
+++ b/microdroid/sepolicy/system/private/microdroid_manager.te
@@ -21,6 +21,12 @@
 # Until then, allow microdroid_manager to execute the shell or other system executables.
 allow microdroid_manager {shell_exec toolbox_exec}:file rx_file_perms;
 
+# Let microdroid_manager kernel-log.
+# TODO(b/189805435) when ready this should be kmsg_device rather than kmsg_debug_device
+userdebug_or_eng(`
+  allow microdroid_manager kmsg_debug_device:chr_file write;
+')
+
 # Let microdroid_manager read a config file from /mnt/apk (fusefs)
 # TODO(b/188400186) remove the below two rules
 userdebug_or_eng(`
diff --git a/microdroid/sepolicy/system/private/wait_for_keymaster.te b/microdroid/sepolicy/system/private/wait_for_keymaster.te
deleted file mode 100644
index da98e2e..0000000
--- a/microdroid/sepolicy/system/private/wait_for_keymaster.te
+++ /dev/null
@@ -1,15 +0,0 @@
-# wait_for_keymaster service
-type wait_for_keymaster, domain, coredomain;
-type wait_for_keymaster_exec, system_file_type, exec_type, file_type;
-
-init_daemon_domain(wait_for_keymaster)
-
-hal_client_domain(wait_for_keymaster, hal_keymaster)
-
-allow wait_for_keymaster kmsg_device:chr_file w_file_perms;
-
-# wait_for_keymaster needs to find keystore and call methods with the returned
-# binder reference.
-binder_use(wait_for_keymaster)
-allow wait_for_keymaster keystore_service:service_manager find;
-binder_call(wait_for_keymaster, keystore)
diff --git a/microdroid/sepolicy/system/private/zipfuse.te b/microdroid/sepolicy/system/private/zipfuse.te
index 65da9d3..fb7527b 100644
--- a/microdroid/sepolicy/system/private/zipfuse.te
+++ b/microdroid/sepolicy/system/private/zipfuse.te
@@ -17,7 +17,9 @@
 # /dev/block/by-name/*
 allow zipfuse block_device:dir r_dir_perms;
 allow zipfuse block_device:lnk_file r_file_perms;
-allow zipfuse vd_device:blk_file r_file_perms;
+
+# /dev/block/by-name/microdroid-apk is mapped to /dev/block/dm-*
+allow zipfuse dm_device:blk_file r_file_perms;
 
 # allow mounting on /mnt/apk
 allow zipfuse tmpfs:dir mounton;
diff --git a/microdroid/sepolicy/vendor/file.te b/microdroid/sepolicy/vendor/file.te
deleted file mode 100644
index 0b1fd74..0000000
--- a/microdroid/sepolicy/vendor/file.te
+++ /dev/null
@@ -1,2 +0,0 @@
-type hostapd_data_file, file_type, data_file_type;
-type wpa_data_file, file_type, data_file_type;
diff --git a/microdroid/sepolicy/vendor/hal_atrace_default.te b/microdroid/sepolicy/vendor/hal_atrace_default.te
deleted file mode 100644
index 55c9730..0000000
--- a/microdroid/sepolicy/vendor/hal_atrace_default.te
+++ /dev/null
@@ -1,14 +0,0 @@
-type hal_atrace_default, domain;
-hal_server_domain(hal_atrace_default, hal_atrace)
-
-type hal_atrace_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_atrace_default)
-
-# Allow atrace HAL to access tracefs.
-allow hal_atrace_default debugfs_tracing:dir r_dir_perms;
-allow hal_atrace_default debugfs_tracing:file rw_file_perms;
-
-userdebug_or_eng(`
-  allow hal_atrace_default debugfs_tracing_debug:dir r_dir_perms;
-  allow hal_atrace_default debugfs_tracing_debug:file rw_file_perms;
-')
diff --git a/microdroid/sepolicy/vendor/hal_audio_default.te b/microdroid/sepolicy/vendor/hal_audio_default.te
deleted file mode 100644
index 82cbf8e..0000000
--- a/microdroid/sepolicy/vendor/hal_audio_default.te
+++ /dev/null
@@ -1,10 +0,0 @@
-type hal_audio_default, domain;
-hal_server_domain(hal_audio_default, hal_audio)
-
-type hal_audio_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_audio_default)
-
-hal_client_domain(hal_audio_default, hal_allocator)
-
-# allow audioserver to call hal_audio dump with its own fd to retrieve status
-allow hal_audio_default audioserver:fifo_file write;
diff --git a/microdroid/sepolicy/vendor/hal_audiocontrol_default.te b/microdroid/sepolicy/vendor/hal_audiocontrol_default.te
deleted file mode 100644
index d1940c9..0000000
--- a/microdroid/sepolicy/vendor/hal_audiocontrol_default.te
+++ /dev/null
@@ -1,7 +0,0 @@
-# audiocontrol subsystem
-type hal_audiocontrol_default, domain;
-hal_server_domain(hal_audiocontrol_default, hal_audiocontrol)
-
-# may be started by init
-type hal_audiocontrol_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_audiocontrol_default)
diff --git a/microdroid/sepolicy/vendor/hal_authsecret_default.te b/microdroid/sepolicy/vendor/hal_authsecret_default.te
deleted file mode 100644
index 46f5291..0000000
--- a/microdroid/sepolicy/vendor/hal_authsecret_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_authsecret_default, domain;
-hal_server_domain(hal_authsecret_default, hal_authsecret)
-
-type hal_authsecret_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_authsecret_default)
diff --git a/microdroid/sepolicy/vendor/hal_bluetooth_btlinux.te b/microdroid/sepolicy/vendor/hal_bluetooth_btlinux.te
deleted file mode 100644
index 22d9cf0..0000000
--- a/microdroid/sepolicy/vendor/hal_bluetooth_btlinux.te
+++ /dev/null
@@ -1,8 +0,0 @@
-type hal_bluetooth_btlinux, domain;
-type hal_bluetooth_btlinux_exec, exec_type, file_type, vendor_file_type;
-
-hal_server_domain(hal_bluetooth_btlinux, hal_bluetooth)
-init_daemon_domain(hal_bluetooth_btlinux)
-
-allow hal_bluetooth_btlinux self:socket { create bind read write };
-allow hal_bluetooth_btlinux self:bluetooth_socket { create bind read write };
diff --git a/microdroid/sepolicy/vendor/hal_bluetooth_default.te b/microdroid/sepolicy/vendor/hal_bluetooth_default.te
deleted file mode 100644
index 01d60db..0000000
--- a/microdroid/sepolicy/vendor/hal_bluetooth_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_bluetooth_default, domain;
-hal_server_domain(hal_bluetooth_default, hal_bluetooth)
-
-type hal_bluetooth_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_bluetooth_default)
diff --git a/microdroid/sepolicy/vendor/hal_bootctl_default.te b/microdroid/sepolicy/vendor/hal_bootctl_default.te
deleted file mode 100644
index 2b94313..0000000
--- a/microdroid/sepolicy/vendor/hal_bootctl_default.te
+++ /dev/null
@@ -1,16 +0,0 @@
-# Boot control subsystem
-type hal_bootctl_default, domain;
-hal_server_domain(hal_bootctl_default, hal_bootctl)
-
-type hal_bootctl_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_bootctl_default)
-
-# Needed for ReadDefaultFstab.
-allow hal_bootctl_default proc_cmdline:file r_file_perms;
-allow hal_bootctl_default sysfs_dt_firmware_android:dir search;
-allow hal_bootctl_default sysfs_dt_firmware_android:file r_file_perms;
-read_fstab(hal_bootctl_default)
-
-# Needed for reading/writing misc partition.
-allow hal_bootctl_default block_device:dir search;
-allow hal_bootctl_default misc_block_device:blk_file rw_file_perms;
diff --git a/microdroid/sepolicy/vendor/hal_broadcastradio_default.te b/microdroid/sepolicy/vendor/hal_broadcastradio_default.te
deleted file mode 100644
index 37f65f4..0000000
--- a/microdroid/sepolicy/vendor/hal_broadcastradio_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_broadcastradio_default, domain;
-hal_server_domain(hal_broadcastradio_default, hal_broadcastradio)
-
-type hal_broadcastradio_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_broadcastradio_default)
diff --git a/microdroid/sepolicy/vendor/hal_camera_default.te b/microdroid/sepolicy/vendor/hal_camera_default.te
deleted file mode 100644
index 5bc4a61..0000000
--- a/microdroid/sepolicy/vendor/hal_camera_default.te
+++ /dev/null
@@ -1,11 +0,0 @@
-type hal_camera_default, domain;
-hal_server_domain(hal_camera_default, hal_camera)
-
-type hal_camera_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_camera_default)
-
-allow hal_camera_default fwk_sensor_hwservice:hwservice_manager find;
-
-# For collecting bugreports.
-allow hal_camera_default dumpstate:fd use;
-allow hal_camera_default dumpstate:fifo_file write;
diff --git a/microdroid/sepolicy/vendor/hal_can_socketcan.te b/microdroid/sepolicy/vendor/hal_can_socketcan.te
deleted file mode 100644
index 7498788..0000000
--- a/microdroid/sepolicy/vendor/hal_can_socketcan.te
+++ /dev/null
@@ -1,38 +0,0 @@
-type hal_can_socketcan, domain;
-hal_server_domain(hal_can_socketcan, hal_can_controller)
-hal_server_domain(hal_can_socketcan, hal_can_bus)
-
-type hal_can_socketcan_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_can_socketcan)
-
-# Managing SocketCAN interfaces
-allow hal_can_socketcan self:capability net_admin;
-allow hal_can_socketcan self:netlink_route_socket { create bind write nlmsg_write read };
-
-# Calling if_nametoindex(3) to open CAN sockets
-allow hal_can_socketcan self:udp_socket { create ioctl };
-allowxperm hal_can_socketcan self:udp_socket ioctl {
-    SIOCGIFINDEX
-};
-
-# Communicating with SocketCAN interfaces and bringing them up/down
-allow hal_can_socketcan self:can_socket { bind create read write ioctl setopt };
-allowxperm hal_can_socketcan self:can_socket ioctl {
-    SIOCGIFFLAGS
-    SIOCSIFFLAGS
-};
-
-# Un-publishing ICanBus interfaces
-allow hal_can_socketcan hidl_manager_hwservice:hwservice_manager find;
-
-allow hal_can_socketcan sysfs:dir r_dir_perms;
-
-allow hal_can_socketcan usb_serial_device:chr_file { ioctl read write open };
-allowxperm hal_can_socketcan usb_serial_device:chr_file ioctl {
-    TCGETS
-    TCSETSW
-    TIOCGSERIAL
-    TIOCSSERIAL
-    TIOCSETD
-    SIOCGIFNAME
-};
diff --git a/microdroid/sepolicy/vendor/hal_cas_default.te b/microdroid/sepolicy/vendor/hal_cas_default.te
deleted file mode 100644
index cc1a2c8..0000000
--- a/microdroid/sepolicy/vendor/hal_cas_default.te
+++ /dev/null
@@ -1,10 +0,0 @@
-type hal_cas_default, domain;
-hal_server_domain(hal_cas_default, hal_cas)
-
-type hal_cas_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_cas_default)
-
-# Allow CAS HAL's default implementation to use vendor-binder service
-vndbinder_use(hal_cas_default);
-
-allow hal_cas_default hal_allocator:fd use;
diff --git a/microdroid/sepolicy/vendor/hal_configstore_default.te b/microdroid/sepolicy/vendor/hal_configstore_default.te
deleted file mode 100644
index cc61a16..0000000
--- a/microdroid/sepolicy/vendor/hal_configstore_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_configstore_default, domain;
-hal_server_domain(hal_configstore_default, hal_configstore)
-
-type hal_configstore_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_configstore_default)
diff --git a/microdroid/sepolicy/vendor/hal_confirmationui_default.te b/microdroid/sepolicy/vendor/hal_confirmationui_default.te
deleted file mode 100644
index 832c687..0000000
--- a/microdroid/sepolicy/vendor/hal_confirmationui_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_confirmationui_default, domain;
-hal_server_domain(hal_confirmationui_default, hal_confirmationui)
-
-type hal_confirmationui_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_confirmationui_default)
diff --git a/microdroid/sepolicy/vendor/hal_contexthub_default.te b/microdroid/sepolicy/vendor/hal_contexthub_default.te
deleted file mode 100644
index b29808d..0000000
--- a/microdroid/sepolicy/vendor/hal_contexthub_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_contexthub_default, domain;
-hal_server_domain(hal_contexthub_default, hal_contexthub)
-
-type hal_contexthub_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_contexthub_default)
diff --git a/microdroid/sepolicy/vendor/hal_drm_default.te b/microdroid/sepolicy/vendor/hal_drm_default.te
deleted file mode 100644
index e534762..0000000
--- a/microdroid/sepolicy/vendor/hal_drm_default.te
+++ /dev/null
@@ -1,8 +0,0 @@
-type hal_drm_default, domain;
-hal_server_domain(hal_drm_default, hal_drm)
-
-type hal_drm_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_drm_default)
-
-allow hal_drm_default hal_codec2_server:fd use;
-allow hal_drm_default hal_omx_server:fd use;
diff --git a/microdroid/sepolicy/vendor/hal_dumpstate_default.te b/microdroid/sepolicy/vendor/hal_dumpstate_default.te
deleted file mode 100644
index 6fbf40f..0000000
--- a/microdroid/sepolicy/vendor/hal_dumpstate_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_dumpstate_default, domain;
-hal_server_domain(hal_dumpstate_default, hal_dumpstate)
-
-type hal_dumpstate_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_dumpstate_default)
diff --git a/microdroid/sepolicy/vendor/hal_evs_default.te b/microdroid/sepolicy/vendor/hal_evs_default.te
deleted file mode 100644
index 57a0299..0000000
--- a/microdroid/sepolicy/vendor/hal_evs_default.te
+++ /dev/null
@@ -1,15 +0,0 @@
-# evs_mock mock hardware driver service
-type hal_evs_default, domain;
-hal_server_domain(hal_evs_default, hal_evs)
-
-# allow init to launch processes in this context
-type hal_evs_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_evs_default)
-
-allow hal_evs_default hal_graphics_allocator_server:fd use;
-
-# allow to use surface flinger
-allow hal_evs_default automotive_display_service_server:fd use;
-
-# allow to use automotive display service
-allow hal_evs_default fwk_automotive_display_hwservice:hwservice_manager find;
diff --git a/microdroid/sepolicy/vendor/hal_face_default.te b/microdroid/sepolicy/vendor/hal_face_default.te
deleted file mode 100644
index 891d1f4..0000000
--- a/microdroid/sepolicy/vendor/hal_face_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_face_default, domain;
-hal_server_domain(hal_face_default, hal_face)
-
-type hal_face_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_face_default)
diff --git a/microdroid/sepolicy/vendor/hal_fingerprint_default.te b/microdroid/sepolicy/vendor/hal_fingerprint_default.te
deleted file mode 100644
index 638b603..0000000
--- a/microdroid/sepolicy/vendor/hal_fingerprint_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_fingerprint_default, domain;
-hal_server_domain(hal_fingerprint_default, hal_fingerprint)
-
-type hal_fingerprint_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_fingerprint_default)
diff --git a/microdroid/sepolicy/vendor/hal_gatekeeper_default.te b/microdroid/sepolicy/vendor/hal_gatekeeper_default.te
deleted file mode 100644
index a3654cc..0000000
--- a/microdroid/sepolicy/vendor/hal_gatekeeper_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_gatekeeper_default, domain;
-hal_server_domain(hal_gatekeeper_default, hal_gatekeeper)
-
-type hal_gatekeeper_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_gatekeeper_default);
diff --git a/microdroid/sepolicy/vendor/hal_gnss_default.te b/microdroid/sepolicy/vendor/hal_gnss_default.te
deleted file mode 100644
index cea362f..0000000
--- a/microdroid/sepolicy/vendor/hal_gnss_default.te
+++ /dev/null
@@ -1,7 +0,0 @@
-type hal_gnss_default, domain;
-hal_server_domain(hal_gnss_default, hal_gnss)
-
-type hal_gnss_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_gnss_default)
-
-allow hal_gnss_default gnss_device:chr_file rw_file_perms;
diff --git a/microdroid/sepolicy/vendor/hal_graphics_allocator_default.te b/microdroid/sepolicy/vendor/hal_graphics_allocator_default.te
deleted file mode 100644
index a129ad4..0000000
--- a/microdroid/sepolicy/vendor/hal_graphics_allocator_default.te
+++ /dev/null
@@ -1,10 +0,0 @@
-type hal_graphics_allocator_default, domain;
-type hal_graphics_allocator_default_tmpfs, file_type;
-hal_server_domain(hal_graphics_allocator_default, hal_graphics_allocator)
-
-type hal_graphics_allocator_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_graphics_allocator_default)
-tmpfs_domain(hal_graphics_allocator_default)
-
-# b/70180742
-dontaudit hal_graphics_allocator_default unlabeled:dir search;
diff --git a/microdroid/sepolicy/vendor/hal_graphics_composer_default.te b/microdroid/sepolicy/vendor/hal_graphics_composer_default.te
deleted file mode 100644
index 7dcd2b2..0000000
--- a/microdroid/sepolicy/vendor/hal_graphics_composer_default.te
+++ /dev/null
@@ -1,10 +0,0 @@
-type hal_graphics_composer_default, domain;
-hal_server_domain(hal_graphics_composer_default, hal_graphics_composer)
-
-type hal_graphics_composer_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_graphics_composer_default)
-type_transition hal_graphics_composer_default tmpfs:file hal_graphics_composer_server_tmpfs;
-allow hal_graphics_composer_default hal_graphics_composer_server_tmpfs:file { getattr map read write };
-
-# b/68864350
-dontaudit hal_graphics_composer_default unlabeled:dir search;
diff --git a/microdroid/sepolicy/vendor/hal_health_default.te b/microdroid/sepolicy/vendor/hal_health_default.te
deleted file mode 100644
index 9b2b921..0000000
--- a/microdroid/sepolicy/vendor/hal_health_default.te
+++ /dev/null
@@ -1,6 +0,0 @@
-# health info abstraction
-type hal_health_default, domain;
-hal_server_domain(hal_health_default, hal_health)
-
-type hal_health_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_health_default)
diff --git a/microdroid/sepolicy/vendor/hal_health_storage_default.te b/microdroid/sepolicy/vendor/hal_health_storage_default.te
deleted file mode 100644
index 37b3e24..0000000
--- a/microdroid/sepolicy/vendor/hal_health_storage_default.te
+++ /dev/null
@@ -1,6 +0,0 @@
-type hal_health_storage_default, domain;
-hal_server_domain(hal_health_storage_default, hal_health_storage)
-
-type hal_health_storage_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_health_storage_default)
-
diff --git a/microdroid/sepolicy/vendor/hal_identity_default.te b/microdroid/sepolicy/vendor/hal_identity_default.te
deleted file mode 100644
index 7f84687..0000000
--- a/microdroid/sepolicy/vendor/hal_identity_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_identity_default, domain;
-hal_server_domain(hal_identity_default, hal_identity)
-
-type hal_identity_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_identity_default)
diff --git a/microdroid/sepolicy/vendor/hal_input_classifier_default.te b/microdroid/sepolicy/vendor/hal_input_classifier_default.te
deleted file mode 100644
index 915cc78..0000000
--- a/microdroid/sepolicy/vendor/hal_input_classifier_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_input_classifier_default, domain;
-hal_server_domain(hal_input_classifier_default, hal_input_classifier)
-
-type hal_input_classifier_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_input_classifier_default)
diff --git a/microdroid/sepolicy/vendor/hal_ir_default.te b/microdroid/sepolicy/vendor/hal_ir_default.te
deleted file mode 100644
index 943aab0..0000000
--- a/microdroid/sepolicy/vendor/hal_ir_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_ir_default, domain;
-hal_server_domain(hal_ir_default, hal_ir)
-
-type hal_ir_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_ir_default)
diff --git a/microdroid/sepolicy/vendor/hal_keymaster_default.te b/microdroid/sepolicy/vendor/hal_keymaster_default.te
deleted file mode 100644
index 6f0d82a..0000000
--- a/microdroid/sepolicy/vendor/hal_keymaster_default.te
+++ /dev/null
@@ -1,7 +0,0 @@
-type hal_keymaster_default, domain;
-hal_server_domain(hal_keymaster_default, hal_keymaster)
-
-type hal_keymaster_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_keymaster_default)
-
-get_prop(hal_keymaster_default, vendor_security_patch_level_prop);
diff --git a/microdroid/sepolicy/vendor/hal_light_default.te b/microdroid/sepolicy/vendor/hal_light_default.te
deleted file mode 100644
index c7fa9a1..0000000
--- a/microdroid/sepolicy/vendor/hal_light_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_light_default, domain;
-hal_server_domain(hal_light_default, hal_light)
-
-type hal_light_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_light_default)
diff --git a/microdroid/sepolicy/vendor/hal_lowpan_default.te b/microdroid/sepolicy/vendor/hal_lowpan_default.te
deleted file mode 100644
index a49bf24..0000000
--- a/microdroid/sepolicy/vendor/hal_lowpan_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_lowpan_default, domain;
-type hal_lowpan_default_exec, exec_type, vendor_file_type, file_type;
-
-hal_server_domain(hal_lowpan_default, hal_lowpan)
-init_daemon_domain(hal_lowpan_default)
diff --git a/microdroid/sepolicy/vendor/hal_memtrack_default.te b/microdroid/sepolicy/vendor/hal_memtrack_default.te
deleted file mode 100644
index c547699..0000000
--- a/microdroid/sepolicy/vendor/hal_memtrack_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_memtrack_default, domain;
-hal_server_domain(hal_memtrack_default, hal_memtrack)
-
-type hal_memtrack_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_memtrack_default)
diff --git a/microdroid/sepolicy/vendor/hal_nfc_default.te b/microdroid/sepolicy/vendor/hal_nfc_default.te
deleted file mode 100644
index c13baa7..0000000
--- a/microdroid/sepolicy/vendor/hal_nfc_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_nfc_default, domain;
-hal_server_domain(hal_nfc_default, hal_nfc)
-
-type hal_nfc_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_nfc_default)
diff --git a/microdroid/sepolicy/vendor/hal_oemlock_default.te b/microdroid/sepolicy/vendor/hal_oemlock_default.te
deleted file mode 100644
index 8597f2c..0000000
--- a/microdroid/sepolicy/vendor/hal_oemlock_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_oemlock_default, domain;
-hal_server_domain(hal_oemlock_default, hal_oemlock)
-
-type hal_oemlock_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_oemlock_default)
diff --git a/microdroid/sepolicy/vendor/hal_power_default.te b/microdroid/sepolicy/vendor/hal_power_default.te
deleted file mode 100644
index 3be4f22..0000000
--- a/microdroid/sepolicy/vendor/hal_power_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_power_default, domain;
-hal_server_domain(hal_power_default, hal_power)
-
-type hal_power_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_power_default)
diff --git a/microdroid/sepolicy/vendor/hal_power_stats_default.te b/microdroid/sepolicy/vendor/hal_power_stats_default.te
deleted file mode 100644
index b7a2c02..0000000
--- a/microdroid/sepolicy/vendor/hal_power_stats_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_power_stats_default, domain;
-hal_server_domain(hal_power_stats_default, hal_power_stats)
-
-type hal_power_stats_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_power_stats_default)
diff --git a/microdroid/sepolicy/vendor/hal_radio_config_default.te b/microdroid/sepolicy/vendor/hal_radio_config_default.te
deleted file mode 100644
index ccbe5bf..0000000
--- a/microdroid/sepolicy/vendor/hal_radio_config_default.te
+++ /dev/null
@@ -1,6 +0,0 @@
-type hal_radio_config_default, domain;
-hal_server_domain(hal_radio_config_default, hal_telephony)
-
-type hal_radio_config_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_radio_config_default)
-
diff --git a/microdroid/sepolicy/vendor/hal_radio_default.te b/microdroid/sepolicy/vendor/hal_radio_default.te
deleted file mode 100644
index 82fd40e..0000000
--- a/microdroid/sepolicy/vendor/hal_radio_default.te
+++ /dev/null
@@ -1,6 +0,0 @@
-type hal_radio_default, domain;
-hal_server_domain(hal_radio_default, hal_telephony)
-
-type hal_radio_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_radio_default)
-
diff --git a/microdroid/sepolicy/vendor/hal_rebootescrow_default.te b/microdroid/sepolicy/vendor/hal_rebootescrow_default.te
deleted file mode 100644
index 2625693..0000000
--- a/microdroid/sepolicy/vendor/hal_rebootescrow_default.te
+++ /dev/null
@@ -1,10 +0,0 @@
-type hal_rebootescrow_default, domain;
-hal_server_domain(hal_rebootescrow_default, hal_rebootescrow)
-get_prop(hal_rebootescrow_default, rebootescrow_hal_prop);
-
-type hal_rebootescrow_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_rebootescrow_default)
-
-type rebootescrow_device, dev_type;
-allow hal_rebootescrow_default rebootescrow_device:{ chr_file blk_file } rw_file_perms;
-allow hal_rebootescrow_default block_device:dir search;
diff --git a/microdroid/sepolicy/vendor/hal_secure_element_default.te b/microdroid/sepolicy/vendor/hal_secure_element_default.te
deleted file mode 100644
index b1a94a1..0000000
--- a/microdroid/sepolicy/vendor/hal_secure_element_default.te
+++ /dev/null
@@ -1,7 +0,0 @@
-type hal_secure_element_default, domain;
-hal_server_domain(hal_secure_element_default, hal_secure_element)
-type hal_secure_element_default_exec, exec_type, vendor_file_type, file_type;
-
-allow hal_secure_element_default secure_element_device:chr_file rw_file_perms;
-
-init_daemon_domain(hal_secure_element_default)
diff --git a/microdroid/sepolicy/vendor/hal_sensors_default.te b/microdroid/sepolicy/vendor/hal_sensors_default.te
deleted file mode 100644
index 8752364..0000000
--- a/microdroid/sepolicy/vendor/hal_sensors_default.te
+++ /dev/null
@@ -1,23 +0,0 @@
-type hal_sensors_default, domain;
-hal_server_domain(hal_sensors_default, hal_sensors)
-
-type hal_sensors_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_sensors_default)
-
-allow hal_sensors_default fwk_scheduler_hwservice:hwservice_manager find;
-
-allow hal_sensors_default input_device:dir r_dir_perms;
-allow hal_sensors_default input_device:chr_file r_file_perms;
-
-# Allow sensor hals to access and use gralloc memory allocated by
-# android.hardware.graphics.allocator
-allow hal_sensors_default hal_graphics_allocator_default:fd use;
-allow hal_sensors_default ion_device:chr_file r_file_perms;
-allow hal_sensors_default dmabuf_system_heap_device:chr_file r_file_perms;
-
-# allow sensor hal to use lock for keeping system awake for wake up
-# events delivery.
-wakelock_use(hal_sensors_default);
-
-# allow sensor hal to use ashmem fd from system_server.
-allow hal_sensors_default system_server:fd use;
diff --git a/microdroid/sepolicy/vendor/hal_tetheroffload_default.te b/microdroid/sepolicy/vendor/hal_tetheroffload_default.te
deleted file mode 100644
index 03c542b..0000000
--- a/microdroid/sepolicy/vendor/hal_tetheroffload_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_tetheroffload_default, domain;
-hal_server_domain(hal_tetheroffload_default, hal_tetheroffload)
-
-type hal_tetheroffload_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_tetheroffload_default)
diff --git a/microdroid/sepolicy/vendor/hal_thermal_default.te b/microdroid/sepolicy/vendor/hal_thermal_default.te
deleted file mode 100644
index 73b2eff..0000000
--- a/microdroid/sepolicy/vendor/hal_thermal_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_thermal_default, domain;
-hal_server_domain(hal_thermal_default, hal_thermal)
-
-type hal_thermal_default_exec, exec_type, vendor_file_type, vendor_file_type, file_type;
-init_daemon_domain(hal_thermal_default)
diff --git a/microdroid/sepolicy/vendor/hal_tv_cec_default.te b/microdroid/sepolicy/vendor/hal_tv_cec_default.te
deleted file mode 100644
index 080e73b..0000000
--- a/microdroid/sepolicy/vendor/hal_tv_cec_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_tv_cec_default, domain;
-hal_server_domain(hal_tv_cec_default, hal_tv_cec)
-
-type hal_tv_cec_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_tv_cec_default)
diff --git a/microdroid/sepolicy/vendor/hal_tv_input_default.te b/microdroid/sepolicy/vendor/hal_tv_input_default.te
deleted file mode 100644
index 12d9743..0000000
--- a/microdroid/sepolicy/vendor/hal_tv_input_default.te
+++ /dev/null
@@ -1,6 +0,0 @@
-type hal_tv_input_default, domain;
-hal_server_domain(hal_tv_input_default, hal_tv_input)
-
-type hal_tv_input_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_tv_input_default)
-
diff --git a/microdroid/sepolicy/vendor/hal_tv_tuner_default.te b/microdroid/sepolicy/vendor/hal_tv_tuner_default.te
deleted file mode 100644
index 639c7bd..0000000
--- a/microdroid/sepolicy/vendor/hal_tv_tuner_default.te
+++ /dev/null
@@ -1,10 +0,0 @@
-type hal_tv_tuner_default, domain;
-hal_server_domain(hal_tv_tuner_default, hal_tv_tuner)
-
-type hal_tv_tuner_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_tv_tuner_default)
-
-allow hal_tv_tuner_default ion_device:chr_file r_file_perms;
-
-# Access to /dev/dma_heap/system
-allow hal_tv_tuner_default dmabuf_system_heap_device:chr_file r_file_perms;
diff --git a/microdroid/sepolicy/vendor/hal_usb_default.te b/microdroid/sepolicy/vendor/hal_usb_default.te
deleted file mode 100644
index 5642a2a..0000000
--- a/microdroid/sepolicy/vendor/hal_usb_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_usb_default, domain;
-hal_server_domain(hal_usb_default, hal_usb)
-
-type hal_usb_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_usb_default)
diff --git a/microdroid/sepolicy/vendor/hal_usb_gadget_default.te b/microdroid/sepolicy/vendor/hal_usb_gadget_default.te
deleted file mode 100644
index f1486b9..0000000
--- a/microdroid/sepolicy/vendor/hal_usb_gadget_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_usb_gadget_default, domain;
-hal_server_domain(hal_usb_gadget_default, hal_usb_gadget)
-
-type hal_usb_gadget_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_usb_gadget_default)
diff --git a/microdroid/sepolicy/vendor/hal_vehicle_default.te b/microdroid/sepolicy/vendor/hal_vehicle_default.te
deleted file mode 100644
index 56a47b7..0000000
--- a/microdroid/sepolicy/vendor/hal_vehicle_default.te
+++ /dev/null
@@ -1,10 +0,0 @@
-# vehicle subsystem
-type hal_vehicle_default, domain;
-hal_server_domain(hal_vehicle_default, hal_vehicle)
-
-# may be started by init
-type hal_vehicle_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_vehicle_default)
-
-# communication with CAN bus HAL
-hal_client_domain(hal_vehicle_default, hal_can_bus)
diff --git a/microdroid/sepolicy/vendor/hal_vibrator_default.te b/microdroid/sepolicy/vendor/hal_vibrator_default.te
deleted file mode 100644
index 6c10d8a..0000000
--- a/microdroid/sepolicy/vendor/hal_vibrator_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_vibrator_default, domain;
-hal_server_domain(hal_vibrator_default, hal_vibrator)
-
-type hal_vibrator_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_vibrator_default)
diff --git a/microdroid/sepolicy/vendor/hal_vr_default.te b/microdroid/sepolicy/vendor/hal_vr_default.te
deleted file mode 100644
index 6a60192..0000000
--- a/microdroid/sepolicy/vendor/hal_vr_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_vr_default, domain;
-hal_server_domain(hal_vr_default, hal_vr)
-
-type hal_vr_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_vr_default)
diff --git a/microdroid/sepolicy/vendor/hal_weaver_default.te b/microdroid/sepolicy/vendor/hal_weaver_default.te
deleted file mode 100644
index 0dd7679..0000000
--- a/microdroid/sepolicy/vendor/hal_weaver_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_weaver_default, domain;
-hal_server_domain(hal_weaver_default, hal_weaver)
-
-type hal_weaver_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_weaver_default)
diff --git a/microdroid/sepolicy/vendor/hal_wifi_default.te b/microdroid/sepolicy/vendor/hal_wifi_default.te
deleted file mode 100644
index 75a9842..0000000
--- a/microdroid/sepolicy/vendor/hal_wifi_default.te
+++ /dev/null
@@ -1,5 +0,0 @@
-type hal_wifi_default, domain;
-hal_server_domain(hal_wifi_default, hal_wifi)
-
-type hal_wifi_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_wifi_default)
diff --git a/microdroid/sepolicy/vendor/hal_wifi_hostapd_default.te b/microdroid/sepolicy/vendor/hal_wifi_hostapd_default.te
deleted file mode 100644
index 1e0dcb8..0000000
--- a/microdroid/sepolicy/vendor/hal_wifi_hostapd_default.te
+++ /dev/null
@@ -1,12 +0,0 @@
-# hostapd or equivalent
-type hal_wifi_hostapd_default, domain;
-hal_server_domain(hal_wifi_hostapd_default, hal_wifi_hostapd)
-type hal_wifi_hostapd_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_wifi_hostapd_default)
-
-net_domain(hal_wifi_hostapd_default)
-
-# Allow hostapd to access it's data folder
-allow hal_wifi_hostapd_default hostapd_data_file:dir create_dir_perms;
-allow hal_wifi_hostapd_default hostapd_data_file:file create_file_perms;
-allow hal_wifi_hostapd_default hostapd_data_file:sock_file create_file_perms;
diff --git a/microdroid/sepolicy/vendor/hal_wifi_supplicant_default.te b/microdroid/sepolicy/vendor/hal_wifi_supplicant_default.te
deleted file mode 100644
index b6b9e09..0000000
--- a/microdroid/sepolicy/vendor/hal_wifi_supplicant_default.te
+++ /dev/null
@@ -1,32 +0,0 @@
-# wpa supplicant or equivalent
-type hal_wifi_supplicant_default, domain;
-hal_server_domain(hal_wifi_supplicant_default, hal_wifi_supplicant)
-type hal_wifi_supplicant_default_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(hal_wifi_supplicant_default)
-
-net_domain(hal_wifi_supplicant_default)
-# Create a socket for receiving info from wpa
-type_transition hal_wifi_supplicant_default wifi_data_file:dir wpa_socket "sockets";
-
-# Allow wpa_supplicant to configure nl80211
-allow hal_wifi_supplicant_default proc_net_type:file write;
-
-# Allow wpa_supplicant to talk to Wifi Keystore HwBinder service.
-hwbinder_use(hal_wifi_supplicant_default)
-allow hal_wifi_supplicant_default system_wifi_keystore_hwservice:hwservice_manager find;
-binder_call(hal_wifi_supplicant_default, wifi_keystore_service_server)
-
-allow hal_wifi_supplicant_default wpa_data_file:dir create_dir_perms;
-allow hal_wifi_supplicant_default wpa_data_file:file create_file_perms;
-allow hal_wifi_supplicant_default wpa_data_file:sock_file create_file_perms;
-
-# Write to security logs for audit.
-get_prop(hal_wifi_supplicant_default, device_logging_prop)
-
-# Devices upgrading to P may grant this permission in device-specific
-# policy along with the data_between_core_and_vendor_violators
-# attribute needed for an exemption.  However, devices that launch with
-# P should use /data/vendor/wifi, which is already granted in core
-# policy.  This is dontaudited here to avoid conditional
-# device-specific behavior in wpa_supplicant.
-dontaudit hal_wifi_supplicant_default wifi_data_file:dir search;
diff --git a/microdroid/sepolicy/vendor/keys.conf b/microdroid/sepolicy/vendor/keys.conf
deleted file mode 100644
index 71ad2c9..0000000
--- a/microdroid/sepolicy/vendor/keys.conf
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# Maps an arbitrary tag [TAGNAME] with the string contents found in
-# TARGET_BUILD_VARIANT. Common convention is to start TAGNAME with an @ and
-# name it after the base file name of the pem file.
-#
-# Each tag (section) then allows one to specify any string found in
-# TARGET_BUILD_VARIANT. Typcially this is user, eng, and userdebug. Another
-# option is to use ALL which will match ANY TARGET_BUILD_VARIANT string.
-#
-
-# Some vendor apps are using platform key for signing.
-# This moves them to untrusted_app domain when the system partition is
-# switched to a Generic System Image (GSI), because the value of platform's
-# seinfo in /system/etc/selinux/plat_mac_permissions.xml has been changed.
-# Duplicating the device-specific platform seinfo into
-# /vendor/etc/selinux/vendor_mac_permissions.xml to make it self-contained
-# within the vendor partition.
-[@PLATFORM]
-ALL : $DEFAULT_SYSTEM_DEV_CERTIFICATE/platform.x509.pem
diff --git a/microdroid/sepolicy/vendor/mac_permissions.xml b/microdroid/sepolicy/vendor/mac_permissions.xml
deleted file mode 100644
index 2d6fab0..0000000
--- a/microdroid/sepolicy/vendor/mac_permissions.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<policy>
-
-<!--
-
-    * A signature is a hex encoded X.509 certificate or a tag defined in
-      keys.conf and is required for each signer tag. The signature can
-      either appear as a set of attached cert child tags or as an attribute.
-    * A signer tag must contain a seinfo tag XOR multiple package stanzas.
-    * Each signer/package tag is allowed to contain one seinfo tag. This tag
-      represents additional info that each app can use in setting a SELinux security
-      context on the eventual process as well as the apps data directory.
-    * seinfo assignments are made according to the following rules:
-      - Stanzas with package name refinements will be checked first.
-      - Stanzas w/o package name refinements will be checked second.
-      - The "default" seinfo label is automatically applied.
-
-    * valid stanzas can take one of the following forms:
-
-     // single cert protecting seinfo
-     <signer signature="@PLATFORM" >
-       <seinfo value="platform" />
-     </signer>
-
-     // multiple certs protecting seinfo (all contained certs must match)
-     <signer>
-       <cert signature="@PLATFORM1"/>
-       <cert signature="@PLATFORM2"/>
-       <seinfo value="platform" />
-     </signer>
-
-     // single cert protecting explicitly named app
-     <signer signature="@PLATFORM" >
-       <package name="com.android.foo">
-         <seinfo value="bar" />
-       </package>
-     </signer>
-
-     // multiple certs protecting explicitly named app (all certs must match)
-     <signer>
-       <cert signature="@PLATFORM1"/>
-       <cert signature="@PLATFORM2"/>
-       <package name="com.android.foo">
-         <seinfo value="bar" />
-       </package>
-     </signer>
--->
-
-    <!-- Vendor dev key in AOSP -->
-    <signer signature="@PLATFORM" >
-      <seinfo value="platform" />
-    </signer>
-</policy>
diff --git a/microdroid/sepolicy/vendor/mediacodec.te b/microdroid/sepolicy/vendor/mediacodec.te
deleted file mode 100644
index f78b58f..0000000
--- a/microdroid/sepolicy/vendor/mediacodec.te
+++ /dev/null
@@ -1,38 +0,0 @@
-type mediacodec, domain, mlstrustedsubject;
-type mediacodec_exec, exec_type, vendor_file_type, file_type;
-
-init_daemon_domain(mediacodec)
-
-# can route /dev/binder traffic to /dev/vndbinder
-vndbinder_use(mediacodec)
-
-hal_server_domain(mediacodec, hal_codec2)
-hal_server_domain(mediacodec, hal_omx)
-
-# mediacodec may use an input surface from a different Codec2 or OMX service
-hal_client_domain(mediacodec, hal_codec2)
-hal_client_domain(mediacodec, hal_omx)
-
-hal_client_domain(mediacodec, hal_allocator)
-hal_client_domain(mediacodec, hal_graphics_allocator)
-
-allow mediacodec gpu_device:chr_file rw_file_perms;
-allow mediacodec ion_device:chr_file rw_file_perms;
-allow mediacodec dmabuf_system_heap_device:chr_file r_file_perms;
-allow mediacodec video_device:chr_file rw_file_perms;
-allow mediacodec video_device:dir search;
-
-crash_dump_fallback(mediacodec)
-
-# get aac_drc_* properties
-get_prop(mediacodec, aac_drc_prop)
-
-# mediacodec should never execute any executable without a domain transition
-neverallow mediacodec { file_type fs_type }:file execute_no_trans;
-
-# Media processing code is inherently risky and thus should have limited
-# permissions and be isolated from the rest of the system and network.
-# Lengthier explanation here:
-# https://android-developers.googleblog.com/2016/05/hardening-media-stack.html
-neverallow mediacodec domain:{ tcp_socket udp_socket rawip_socket } *;
-
diff --git a/microdroid/sepolicy/vendor/rild.te b/microdroid/sepolicy/vendor/rild.te
deleted file mode 100644
index fc84ef7..0000000
--- a/microdroid/sepolicy/vendor/rild.te
+++ /dev/null
@@ -1,9 +0,0 @@
-# rild - radio interface layer daemon
-type rild, domain;
-hal_server_domain(rild, hal_telephony)
-net_domain(rild)
-
-# type_transition must be private policy the domain_trans rules could stay
-# public, but conceptually should go with this
-type rild_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(rild)
diff --git a/microdroid/sepolicy/vendor/tee.te b/microdroid/sepolicy/vendor/tee.te
deleted file mode 100644
index 4b2e6c7..0000000
--- a/microdroid/sepolicy/vendor/tee.te
+++ /dev/null
@@ -1,17 +0,0 @@
-##
-# trusted execution environment (tee) daemon
-#
-type tee_exec, exec_type, vendor_file_type, file_type;
-init_daemon_domain(tee)
-
-allow tee self:global_capability_class_set { dac_override };
-allow tee tee_device:chr_file rw_file_perms;
-allow tee tee_data_file:dir rw_dir_perms;
-allow tee tee_data_file:file create_file_perms;
-allow tee self:netlink_socket create_socket_perms_no_ioctl;
-allow tee self:netlink_generic_socket create_socket_perms_no_ioctl;
-allow tee ion_device:chr_file r_file_perms;
-r_dir_file(tee, sysfs_type)
-
-allow tee system_data_file:file { getattr read };
-allow tee system_data_file:lnk_file { getattr read };
diff --git a/microdroid/sepolicy/vendor/vendor_install_recovery.te b/microdroid/sepolicy/vendor/vendor_install_recovery.te
deleted file mode 100644
index ff63f75..0000000
--- a/microdroid/sepolicy/vendor/vendor_install_recovery.te
+++ /dev/null
@@ -1,24 +0,0 @@
-init_daemon_domain(vendor_install_recovery)
-
-# service vendor_flash_recovery in
-# bootable/recovery/applypatch/vendor_flash_recovery.rc
-type vendor_install_recovery, domain;
-type vendor_install_recovery_exec, vendor_file_type, exec_type, file_type;
-
-# /vendor/bin/install-recovery.sh is a shell script.
-# Needs to execute /vendor/bin/sh
-allow vendor_install_recovery vendor_shell_exec:file rx_file_perms;
-
-# Execute /vendor/bin/applypatch
-allow vendor_install_recovery vendor_file:file rx_file_perms;
-not_full_treble(`allow vendor_install_recovery vendor_file:file rx_file_perms;')
-
-allow vendor_install_recovery vendor_toolbox_exec:file rx_file_perms;
-
-# Update the recovery block device based off a diff of the boot block device
-allow vendor_install_recovery block_device:dir search;
-allow vendor_install_recovery boot_block_device:blk_file r_file_perms;
-allow vendor_install_recovery recovery_block_device:blk_file rw_file_perms;
-
-# Write to /proc/sys/vm/drop_caches
-allow vendor_install_recovery proc_drop_caches:file w_file_perms;
diff --git a/microdroid/sepolicy/vendor/vendor_misc_writer.te b/microdroid/sepolicy/vendor/vendor_misc_writer.te
deleted file mode 100644
index 245749e..0000000
--- a/microdroid/sepolicy/vendor/vendor_misc_writer.te
+++ /dev/null
@@ -1 +0,0 @@
-init_daemon_domain(vendor_misc_writer)
diff --git a/microdroid/sepolicy/vendor/vendor_modprobe.te b/microdroid/sepolicy/vendor/vendor_modprobe.te
deleted file mode 100644
index 3f5918c..0000000
--- a/microdroid/sepolicy/vendor/vendor_modprobe.te
+++ /dev/null
@@ -1,11 +0,0 @@
-# For the use of /vendor/bin/modprobe from vendor init.rc fragments
-domain_trans(init, vendor_toolbox_exec, vendor_modprobe)
-
-allow vendor_modprobe proc_modules:file r_file_perms;
-allow vendor_modprobe proc_cmdline:file r_file_perms;
-allow vendor_modprobe kmsg_device:chr_file w_file_perms;
-allow vendor_modprobe self:global_capability_class_set sys_module;
-allow vendor_modprobe kernel:key search;
-
-allow vendor_modprobe { vendor_file }:system module_load;
-r_dir_file(vendor_modprobe, { vendor_file })
diff --git a/microdroid/sepolicy/vendor/vndservice_contexts b/microdroid/sepolicy/vendor/vndservice_contexts
deleted file mode 100644
index 068056f..0000000
--- a/microdroid/sepolicy/vendor/vndservice_contexts
+++ /dev/null
@@ -1,2 +0,0 @@
-manager                 u:object_r:service_manager_vndservice:s0
-*                       u:object_r:default_android_vndservice:s0
diff --git a/microdroid/sepolicy/vendor/vndservicemanager.te b/microdroid/sepolicy/vendor/vndservicemanager.te
deleted file mode 100644
index 497e027..0000000
--- a/microdroid/sepolicy/vendor/vndservicemanager.te
+++ /dev/null
@@ -1,22 +0,0 @@
-# vndservicemanager - the Binder context manager for vendor processes
-type vndservicemanager_exec, exec_type, vendor_file_type, file_type;
-
-init_daemon_domain(vndservicemanager);
-
-allow vndservicemanager self:binder set_context_mgr;
-
-# transfer binder objects to other processes (TODO b/35870313 limit this to vendor-only)
-allow vndservicemanager { domain -coredomain -init -vendor_init }:binder transfer;
-
-allow vndservicemanager vndbinder_device:chr_file rw_file_perms;
-
-# Read vndservice_contexts
-allow vndservicemanager vndservice_contexts_file:file r_file_perms;
-
-add_service(vndservicemanager, service_manager_vndservice)
-
-# Start lazy services
-set_prop(vndservicemanager, ctl_interface_start_prop)
-
-# Check SELinux permissions.
-selinux_check_access(vndservicemanager)
diff --git a/microdroid/uboot-env-x86_64.txt b/microdroid/uboot-env-x86_64.txt
index ffc0462..1abafa6 100644
--- a/microdroid/uboot-env-x86_64.txt
+++ b/microdroid/uboot-env-x86_64.txt
@@ -1,7 +1,9 @@
 # Static u-boot environment variables for microdroid. See b/180481192
 
 # Boot the device following the Android boot procedure
-bootcmd=avb init virtio 0 && avb verify _a && boot_android virtio 0#misc
+# `0` is the disk number of os_composite.img
+# `a` and `_a` are the slot index for A/B
+bootcmd=avb init virtio 0 && avb verify _a && boot_android virtio 0 a
 
 bootdelay=0
 
diff --git a/microdroid/uboot-env.txt b/microdroid/uboot-env.txt
index 0bdc591..585702e 100644
--- a/microdroid/uboot-env.txt
+++ b/microdroid/uboot-env.txt
@@ -1,7 +1,9 @@
 # Static u-boot environment variables for microdroid. See b/180481192
 
 # Boot the device following the Android boot procedure
-bootcmd=avb init virtio 0 && avb verify _a && boot_android virtio 0#misc
+# `0` is the disk number of os_composite.img
+# `a` and `_a` are the slot index for A/B
+bootcmd=avb init virtio 0 && avb verify _a && boot_android virtio 0 a
 
 bootdelay=0
 fdtaddr=0x80000000
diff --git a/microdroid_manager/Android.bp b/microdroid_manager/Android.bp
index cb628b1..30f8481 100644
--- a/microdroid_manager/Android.bp
+++ b/microdroid_manager/Android.bp
@@ -9,7 +9,7 @@
     edition: "2018",
     prefer_rlib: true,
     rustlibs: [
-        "libandroid_logger",
+        "libenv_logger",
         "libanyhow",
         "libkeystore2_system_property-rust",
         "liblog_rust",
diff --git a/microdroid_manager/microdroid_manager.rc b/microdroid_manager/microdroid_manager.rc
index c800002..4f194a3 100644
--- a/microdroid_manager/microdroid_manager.rc
+++ b/microdroid_manager/microdroid_manager.rc
@@ -1,4 +1,7 @@
 service microdroid_manager /system/bin/microdroid_manager
     disabled
+    # TODO(b/189805435) for now redirect stdio to kmsg
+    stdio_to_kmsg
+    setenv RUST_LOG info
     # TODO(jooyung) remove this when microdroid_manager becomes a daemon
     oneshot
\ No newline at end of file
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index ae72a59..10731c5 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -17,10 +17,9 @@
 mod ioutil;
 mod metadata;
 
-use android_logger::Config;
 use anyhow::{anyhow, bail, Result};
 use keystore2_system_property::PropertyWatcher;
-use log::{info, Level};
+use log::info;
 use microdroid_payload_config::{Task, TaskType, VmPayloadConfig};
 use std::fs;
 use std::path::Path;
@@ -29,10 +28,9 @@
 
 const WAIT_TIMEOUT: Duration = Duration::from_secs(10);
 
-const LOG_TAG: &str = "MicrodroidManager";
-
 fn main() -> Result<()> {
-    android_logger::init_once(Config::default().with_tag(LOG_TAG).with_min_level(Level::Debug));
+    // TODO(b/189805435) use kernlog
+    env_logger::init();
 
     info!("started.");
 
@@ -57,8 +55,15 @@
 
 fn exec_task(task: &Task) -> Result<()> {
     info!("executing main task {:?}...", task);
-    build_command(task)?.spawn()?;
-    Ok(())
+    let exit_status = build_command(task)?.spawn()?.wait()?;
+    if exit_status.success() {
+        Ok(())
+    } else {
+        match exit_status.code() {
+            Some(code) => bail!("task exited with exit code: {}", code),
+            None => bail!("task terminated by signal"),
+        }
+    }
 }
 
 fn build_command(task: &Task) -> Result<Command> {
diff --git a/tests/hostside/Android.bp b/tests/hostside/Android.bp
index 429b737..8edd65d 100644
--- a/tests/hostside/Android.bp
+++ b/tests/hostside/Android.bp
@@ -6,5 +6,9 @@
     name: "MicrodroidHostTestCases",
     srcs: ["java/**/*.java"],
     test_suites: ["device-tests"],
-    libs: ["tradefed"],
+    libs: [
+        "tradefed",
+        "compatibility-tradefed",
+    ],
+    data: [":MicrodroidTestApp.signed"],
 }
diff --git a/tests/hostside/AndroidTest.xml b/tests/hostside/AndroidTest.xml
index da24b71..247923d 100644
--- a/tests/hostside/AndroidTest.xml
+++ b/tests/hostside/AndroidTest.xml
@@ -18,6 +18,11 @@
         <option name="force-root" value="true" />
     </target_preparer>
 
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="MicrodroidTestApp.apk" />
+    </target_preparer>
+
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="MicrodroidHostTestCases.jar" />
     </test>
diff --git a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
index a1043f7..5449af0 100644
--- a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
+++ b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
@@ -20,28 +20,37 @@
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.not;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeThat;
 
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 import com.android.tradefed.util.CommandResult;
 import com.android.tradefed.util.CommandStatus;
-import com.android.tradefed.util.FileUtil;
 import com.android.tradefed.util.RunUtil;
 
+import org.json.JSONArray;
+import org.json.JSONObject;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.zip.ZipFile;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class MicrodroidTestCase extends BaseHostJUnit4Test {
@@ -50,140 +59,211 @@
     private static final int TEST_VM_CID = 10;
     private static final int TEST_VM_ADB_PORT = 8000;
     private static final String MICRODROID_SERIAL = "localhost:" + TEST_VM_ADB_PORT;
+
     // This is really slow on GCE (2m 40s) but fast on localhost or actual Android phones (< 10s)
     // Set the maximum timeout value big enough.
     private static final long MICRODROID_BOOT_TIMEOUT_MINUTES = 5;
 
-    private String executeCommand(String cmd) {
-        final long defaultCommandTimeoutMillis = 3000; // 3 sec. Can be slow on GCE
-        return executeCommand(defaultCommandTimeoutMillis, cmd);
-    }
-
-    private String executeCommand(long timeout, String cmd) {
-        CommandResult result = RunUtil.getDefault().runTimedCmd(timeout, cmd.split(" "));
-        return result.getStdout().trim(); // remove the trailing whitespace including newline
-    }
-
-    private String executeCommandOnMicrodroid(String cmd) {
-        cmd = "adb -s " + MICRODROID_SERIAL + " " + cmd;
-        return executeCommand(cmd);
-    }
-
     @Test
     public void testMicrodroidBoots() throws Exception {
-        // Prepare input files
-        String prepareImagesCmd =
-                String.format(
-                        "mkdir -p %s; cd %s; "
-                                + "cp %setc/microdroid_bootloader bootloader && "
-                                + "cp %setc/fs/*.img . && "
-                                + "cp %setc/uboot_env.img . && "
-                                + "dd if=/dev/zero of=misc.img bs=4k count=256",
-                        TEST_ROOT, TEST_ROOT, VIRT_APEX, VIRT_APEX, VIRT_APEX);
-        getDevice().executeShellCommand(prepareImagesCmd);
+        final String apkName = "MicrodroidTestApp.apk";
+        final String packageName = "com.android.microdroid.test";
+        final String configPath = "assets/vm_config.json"; // path inside the APK
+        startMicrodroid(apkName, packageName, configPath);
+        waitForMicrodroidBoot(MICRODROID_BOOT_TIMEOUT_MINUTES);
+        adbConnectToMicrodroid();
 
-        // Create os_composite.img, env_composite.img, and payload.img
-        String makeOsCompositeCmd =
-                String.format(
-                        "cd %s; %sbin/mk_cdisk %setc/microdroid_cdisk.json os_composite.img",
-                        TEST_ROOT, VIRT_APEX, VIRT_APEX);
-        getDevice().executeShellCommand(makeOsCompositeCmd);
-        String makeEnvCompositeCmd =
-                String.format(
-                        "cd %s; %sbin/mk_cdisk %setc/microdroid_cdisk_env.json env_composite.img",
-                        TEST_ROOT, VIRT_APEX, VIRT_APEX);
-        getDevice().executeShellCommand(makeEnvCompositeCmd);
-        String makePayloadCompositeCmd =
-                String.format(
-                        "cd %s; %sbin/mk_payload %setc/microdroid_payload.json payload.img",
-                        TEST_ROOT, VIRT_APEX, VIRT_APEX);
-        getDevice().executeShellCommand(makePayloadCompositeCmd);
+        // Check if it actually booted by reading a sysprop.
+        assertThat(runOnMicrodroid("getprop", "ro.hardware"), is("microdroid"));
 
-        // Make sure that the composite images are created
-        final List<String> compositeImages =
-                new ArrayList<>(
-                        Arrays.asList(
-                                TEST_ROOT + "/os_composite.img",
-                                TEST_ROOT + "/env_composite.img",
-                                TEST_ROOT + "/payload.img"));
+        // Test writing to /data partition
+        runOnMicrodroid("echo MicrodroidTest > /data/local/tmp/test.txt");
+        assertThat(runOnMicrodroid("cat /data/local/tmp/test.txt"), is("MicrodroidTest"));
+
+        // Check if the APK & its idsig partitions exist
+        final String apkPartition = "/dev/block/by-name/microdroid-apk";
+        assertThat(runOnMicrodroid("ls", apkPartition), is(apkPartition));
+        final String apkIdsigPartition = "/dev/block/by-name/microdroid-apk-idsig";
+        assertThat(runOnMicrodroid("ls", apkIdsigPartition), is(apkIdsigPartition));
+
+        // Check if the APK is mounted using zipfuse
+        final String mountEntry = "zipfuse on /mnt/apk type fuse.zipfuse";
+        assertThat(runOnMicrodroid("mount"), containsString(mountEntry));
+
+        // Check if the native library in the APK is has correct filesystem info
+        final String[] abis = runOnMicrodroid("getprop", "ro.product.cpu.abilist").split(",");
+        assertThat(abis.length, is(1));
+        final String testLib = "/mnt/apk/lib/" + abis[0] + "/MicrodroidTestNativeLib.so";
+        final String label = "u:object_r:system_file:s0";
+        assertThat(runOnMicrodroid("ls", "-Z", testLib), is(label + " " + testLib));
+
+        // Check if the command in vm_config.json was executed by examining the side effect of the
+        // command
+        assertThat(runOnMicrodroid("getprop", "debug.microdroid.app.run"), is("true"));
+
+        // Manually execute the library and check the output
+        final String microdroidLauncher = "system/bin/microdroid_launcher";
+        assertThat(
+                runOnMicrodroid(microdroidLauncher, testLib, "arg1", "arg2"),
+                is("Hello Microdroid " + testLib + " arg1 arg2"));
+
+        // Shutdown microdroid
+        runOnMicrodroid("reboot");
+    }
+
+    // Run an arbitrary command in the host side and returns the result
+    private String runOnHost(String... cmd) {
+        final long timeout = 10000;
+        CommandResult result = RunUtil.getDefault().runTimedCmd(timeout, cmd);
+        assertThat(result.getStatus(), is(CommandStatus.SUCCESS));
+        return result.getStdout().trim();
+    }
+
+    // Same as runOnHost, but failure is not an error
+    private String tryRunOnHost(String... cmd) {
+        final long timeout = 10000;
+        CommandResult result = RunUtil.getDefault().runTimedCmd(timeout, cmd);
+        return result.getStdout().trim();
+    }
+
+    // Run a shell command on Android
+    private String runOnAndroid(String... cmd) throws Exception {
+        CommandResult result = getDevice().executeShellV2Command(join(cmd));
+        if (result.getStatus() != CommandStatus.SUCCESS) {
+            fail(join(cmd) + " has failed: " + result);
+        }
+        return result.getStdout().trim();
+    }
+
+    // Same as runOnAndroid, but failutre is not an error
+    private String tryRunOnAndroid(String... cmd) throws Exception {
+        CommandResult result = getDevice().executeShellV2Command(join(cmd));
+        return result.getStdout().trim();
+    }
+
+    // Run a shell command on Microdroid
+    private String runOnMicrodroid(String... cmd) {
+        final long timeout = 30000; // 30 sec. Microdroid is extremely slow on GCE-on-CF.
         CommandResult result =
-                getDevice().executeShellV2Command("du -b " + String.join(" ", compositeImages));
-        assertThat(result.getExitCode(), is(0));
-        assertThat(result.getStdout(), is(not("")));
+                RunUtil.getDefault()
+                        .runTimedCmd(timeout, "adb", "-s", MICRODROID_SERIAL, "shell", join(cmd));
+        if (result.getStatus() != CommandStatus.SUCCESS) {
+            fail(join(cmd) + " has failed: " + result);
+        }
+        return result.getStdout().trim();
+    }
+
+    private String join(String... strs) {
+        return String.join(" ", Arrays.asList(strs));
+    }
+
+    private String createPayloadImage(String apkName, String packageName, String configPath)
+            throws Exception {
+        File apkFile = findTestFile(apkName);
+        getDevice().installPackage(apkFile, /* reinstall */ true);
+
+        // Read the config file from the apk and parse it to know the list of APEXes needed
+        ZipFile apkAsZip = new ZipFile(apkFile);
+        InputStream is = apkAsZip.getInputStream(apkAsZip.getEntry(configPath));
+        String configString =
+                new BufferedReader(new InputStreamReader(is))
+                        .lines()
+                        .collect(Collectors.joining("\n"));
+        JSONObject configObject = new JSONObject(configString);
+        JSONArray apexes = configObject.getJSONArray("apexes");
+        List<String> apexNames = new ArrayList<>();
+        for (int i = 0; i < apexes.length(); i++) {
+            JSONObject anApex = apexes.getJSONObject(i);
+            apexNames.add(anApex.getString("name"));
+        }
+
+        // Get the path to the installed apk. Note that
+        // getDevice().getAppPackageInfo(...).getCodePath() doesn't work due to the incorrect
+        // parsing of the "=" character. (b/190975227). So we use the `pm path` command directly.
+        String apkPath = runOnAndroid("pm", "path", packageName);
+        assertTrue(apkPath.startsWith("package:"));
+        apkPath = apkPath.substring("package:".length());
+
+        // Push the idsig file to the device
+        File idsigOnHost = findTestFile(apkName + ".idsig");
+        final String apkIdsigPath = TEST_ROOT + apkName + ".idsig";
+        getDevice().pushFile(idsigOnHost, apkIdsigPath);
+
+        // Create payload.json from the gathered data
+        JSONObject payloadObject = new JSONObject();
+        payloadObject.put("system_apexes", new JSONArray(apexNames));
+        payloadObject.put("payload_config_path", "/mnt/apk/" + configPath);
+        JSONObject apkObject = new JSONObject();
+        apkObject.put("name", packageName);
+        apkObject.put("path", apkPath);
+        apkObject.put("idsig_path", apkIdsigPath);
+        payloadObject.put("apk", apkObject);
+
+        // Copy the json file to Android
+        File payloadJsonOnHost = File.createTempFile("payload", "json");
+        FileWriter writer = new FileWriter(payloadJsonOnHost);
+        writer.write(payloadObject.toString());
+        writer.close();
+        final String payloadJson = TEST_ROOT + "payload.json";
+        getDevice().pushFile(payloadJsonOnHost, payloadJson);
+
+        // Finally run mk_payload to create payload.img
+        final String mkPayload = VIRT_APEX + "bin/mk_payload";
+        final String payloadImg = TEST_ROOT + "payload.img";
+        runOnAndroid(mkPayload, payloadJson, payloadImg);
+        assertThat(runOnAndroid("du", "-b", payloadImg), is(not("")));
+
+        return payloadImg;
+    }
+
+    private File findTestFile(String name) throws Exception {
+        return (new CompatibilityBuildHelper(getBuild())).getTestFile(name);
+    }
+
+    private void startMicrodroid(String apkName, String packageName, String configPath)
+            throws Exception {
+        // Create payload.img
+        final String payloadImg = createPayloadImage(apkName, packageName, configPath);
+
+        // Tools and executables
+        final String mkCdisk = VIRT_APEX + "bin/mk_cdisk";
+        final String crosvm = VIRT_APEX + "bin/crosvm";
+
+        // Create os_composisite.img and env_composite.img
+        // TODO(jiyong): remove this when running a VM is done by `vm`
+        final String cdiskJson = VIRT_APEX + "etc/microdroid_cdisk.json";
+        final String cdiskEnvJson = VIRT_APEX + "etc/microdroid_cdisk_env.json";
+        final String osImg = TEST_ROOT + "os_composite.img";
+        final String envImg = TEST_ROOT + "env_composite.img";
+        final String bootloader = VIRT_APEX + "etc/microdroid_bootloader";
+        runOnAndroid(mkCdisk, cdiskJson, osImg);
+        runOnAndroid(mkCdisk, cdiskEnvJson, envImg);
 
         // Start microdroid using crosvm
+        // TODO(jiyong): do this via the `vm` command
         ExecutorService executor = Executors.newFixedThreadPool(1);
-        String runMicrodroidCmd =
-                String.format(
-                        "cd %s; %sbin/crosvm run --cid=%d --disable-sandbox --bios=bootloader"
-                                + " --serial=type=syslog --disk=os_composite.img"
-                                + " --disk=env_composite.img --disk=payload.img &",
-                        TEST_ROOT, VIRT_APEX, TEST_VM_CID);
         executor.execute(
                 () -> {
                     try {
-                        getDevice().executeShellV2Command(runMicrodroidCmd);
+                        runOnAndroid(
+                                crosvm,
+                                "run",
+                                "--cid=" + TEST_VM_CID,
+                                "--disable-sandbox",
+                                "--bios=" + bootloader,
+                                "--serial=type=syslog",
+                                "--disk=" + osImg,
+                                "--disk=" + envImg,
+                                "--disk=" + payloadImg,
+                                "&");
                     } catch (Exception e) {
                         throw new RuntimeException(e);
                     }
                 });
-        waitForMicrodroidBoot(MICRODROID_BOOT_TIMEOUT_MINUTES);
-
-        // Connect to microdroid and read a system property from there
-        executeCommand(
-                "adb -s "
-                        + getDevice().getSerialNumber()
-                        + " forward tcp:"
-                        + TEST_VM_ADB_PORT
-                        + " vsock:"
-                        + TEST_VM_CID
-                        + ":5555");
-        executeCommand("adb connect " + MICRODROID_SERIAL);
-        String prop = executeCommandOnMicrodroid("shell getprop ro.hardware");
-        assertThat(prop, is("microdroid"));
-
-        // Test writing to /data partition
-        File tmpFile = FileUtil.createTempFile("test", ".txt");
-        tmpFile.deleteOnExit();
-        FileWriter writer = new FileWriter(tmpFile);
-        writer.write("MicrodroidTest");
-        writer.close();
-
-        executeCommandOnMicrodroid("push " + tmpFile.getPath() + " /data/local/tmp/test.txt");
-        assertThat(
-                executeCommandOnMicrodroid("shell cat /data/local/tmp/test.txt"),
-                is("MicrodroidTest"));
-
-        assertThat(
-                executeCommandOnMicrodroid("shell ls /dev/block/by-name/microdroid-apk"),
-                is("/dev/block/by-name/microdroid-apk"));
-
-        assertThat(
-                executeCommandOnMicrodroid("shell mount"),
-                containsString("zipfuse on /mnt/apk type fuse.zipfuse"));
-
-        final String[] abiList =
-                executeCommandOnMicrodroid("shell getprop ro.product.cpu.abilist").split(",");
-        assertThat(abiList.length, is(1));
-
-        final String libPath = "/mnt/apk/lib/" + abiList[0] + "/MicrodroidTestNativeLib.so";
-        assertThat(
-                executeCommandOnMicrodroid("shell ls -Z " + libPath),
-                is("u:object_r:system_file:s0 " + libPath));
-
-        assertThat(
-                executeCommandOnMicrodroid(
-                        "shell /system/bin/microdroid_launcher " + libPath + " arg1 arg2"),
-                is("Hello Microdroid " + libPath + " arg1 arg2"));
-
-        // Shutdown microdroid
-        executeCommand("adb -s localhost:" + TEST_VM_ADB_PORT + " shell reboot");
     }
 
     private void waitForMicrodroidBoot(long timeoutMinutes) throws Exception {
-        // Wait for a specific log from logd
-        // TODO(jiyong): use a more reasonable marker
-        final String pattern = "logd.auditd: start";
+        final String pattern = "load_persist_props_action";
         getDevice()
                 .executeShellV2Command(
                         "logcat --regex=\"" + pattern + "\" -m 1",
@@ -191,9 +271,19 @@
                         TimeUnit.MINUTES);
     }
 
+    // Establish an adb connection to microdroid by letting Android forward the connection to
+    // microdroid.
+    private void adbConnectToMicrodroid() {
+        final String serial = getDevice().getSerialNumber();
+        final String from = "tcp:" + TEST_VM_ADB_PORT;
+        final String to = "vsock:" + TEST_VM_CID + ":5555";
+        runOnHost("adb", "-s", serial, "forward", from, to);
+        runOnHost("adb", "connect", MICRODROID_SERIAL);
+    }
+
     private void skipIfFail(String command) throws Exception {
-        assumeThat(
-                getDevice().executeShellV2Command(command).getStatus(), is(CommandStatus.SUCCESS));
+        CommandResult result = getDevice().executeShellV2Command(command);
+        assumeThat(result.getStatus(), is(CommandStatus.SUCCESS));
     }
 
     @Before
@@ -208,24 +298,25 @@
     @Before
     public void setUp() throws Exception {
         // kill stale crosvm processes
-        getDevice().executeShellV2Command("killall crosvm");
+        tryRunOnAndroid("killall", "crosvm");
 
-        // delete the test root
-        getDevice().executeShellCommand("rm -rf " + TEST_ROOT);
+        // Prepare the test root
+        tryRunOnAndroid("rm", "-rf", TEST_ROOT);
+        tryRunOnAndroid("mkdir", "-p", TEST_ROOT);
 
         // disconnect from microdroid
-        executeCommand("adb disconnect " + MICRODROID_SERIAL);
+        tryRunOnHost("adb", "disconnect", MICRODROID_SERIAL);
 
         // clear the log
-        getDevice().executeShellV2Command("logcat -c");
+        tryRunOnAndroid("logcat", "-c");
     }
 
     @After
     public void shutdown() throws Exception {
         // disconnect from microdroid
-        executeCommand("adb disconnect " + MICRODROID_SERIAL);
+        tryRunOnHost("adb", "disconnect", MICRODROID_SERIAL);
 
         // kill stale crosvm processes
-        getDevice().executeShellV2Command("killall crosvm");
+        tryRunOnAndroid("killall", "crosvm");
     }
 }
diff --git a/tests/testapk/Android.bp b/tests/testapk/Android.bp
index 277ccc8..35f2f08 100644
--- a/tests/testapk/Android.bp
+++ b/tests/testapk/Android.bp
@@ -7,7 +7,7 @@
     srcs: ["src/java/**/*.java"],
     jni_libs: ["MicrodroidTestNativeLib"],
     sdk_version: "current",
-    apex_available: ["com.android.virt"], // TODO(jiyong): remove this from virt APEX
+    use_embedded_native_libs: true,
 }
 
 // TODO(jiyong): make this a binary, not a shared library
@@ -15,5 +15,21 @@
     name: "MicrodroidTestNativeLib",
     srcs: ["src/native/*.cpp"],
     sdk_version: "current",
-    apex_available: ["com.android.virt"], // TODO(jiyong): remove this from virt APEX
+}
+
+genrule {
+    name: "MicrodroidTestApp.signed",
+    out: [
+        "MicrodroidTestApp.apk",
+        "MicrodroidTestApp.apk.idsig",
+    ],
+    srcs: [":MicrodroidTestApp"],
+    tools:["apksigner"],
+    tool_files: ["test.keystore"],
+    cmd: "$(location apksigner) sign " +
+         "--ks $(location test.keystore) " +
+         "--ks-pass=pass:testkey --key-pass=pass:testkey " +
+         "--in $(in) " +
+         "--out $(genDir)/MicrodroidTestApp.apk",
+         // $(genDir)/MicrodroidTestApp.apk.idsig is generated implicitly
 }
diff --git a/tests/testapk/assets/vm_config.json b/tests/testapk/assets/vm_config.json
index 7a3df7a..8312f4d 100644
--- a/tests/testapk/assets/vm_config.json
+++ b/tests/testapk/assets/vm_config.json
@@ -9,5 +9,19 @@
       "hello",
       "microdroid"
     ]
-  }
-}
\ No newline at end of file
+  },
+  "apexes": [
+    {
+      "name": "com.android.adbd"
+    },
+    {
+      "name": "com.android.i18n"
+    },
+    {
+      "name": "com.android.os.statsd"
+    },
+    {
+      "name": "com.android.sdkext"
+    }
+  ]
+}
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index c317cd2..c3eefc4 100644
--- a/tests/testapk/src/native/testbinary.cpp
+++ b/tests/testapk/src/native/testbinary.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 #include <stdio.h>
+#include <sys/system_properties.h>
 
 extern "C" int android_native_main(int argc, char* argv[]) {
     printf("Hello Microdroid ");
@@ -25,5 +26,7 @@
         }
     }
     printf("\n");
+
+    __system_property_set("debug.microdroid.app.run", "true");
     return 0;
 }
diff --git a/tests/testapk/test.keystore b/tests/testapk/test.keystore
new file mode 100644
index 0000000..2f024d8
--- /dev/null
+++ b/tests/testapk/test.keystore
Binary files differ
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..6d3f737 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -26,13 +26,14 @@
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::VirtualMachineConfig::VirtualMachineConfig;
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::VirtualMachineDebugInfo::VirtualMachineDebugInfo;
 use android_system_virtualizationservice::binder::{
-    self, BinderFeatures, Interface, ParcelFileDescriptor, StatusCode, Strong, ThreadState,
+    self, BinderFeatures, ExceptionCode, Interface, ParcelFileDescriptor, Status, Strong, ThreadState,
 };
 use command_fds::FdMapping;
+use disk::QcowFile;
 use log::{debug, error, warn};
 use std::convert::TryInto;
+use std::ffi::CString;
 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};
@@ -80,10 +81,16 @@
         let temporary_directory: PathBuf = format!("{}/{}", TEMPORARY_DIRECTORY, cid).into();
         create_dir(&temporary_directory).map_err(|e| {
             error!(
-                "Failed to create temporary directory {:?} for VM files: {:?}",
+                "Failed to create temporary directory {:?} for VM files: {}",
                 temporary_directory, e
             );
-            StatusCode::UNKNOWN_ERROR
+            new_binder_exception(
+                ExceptionCode::SERVICE_SPECIFIC,
+                format!(
+                    "Failed to create temporary directory {:?} for VM files: {}",
+                    temporary_directory, e
+                ),
+            )
         })?;
 
         // Assemble disk images if needed.
@@ -126,8 +133,11 @@
             requester_debug_pid,
         )
         .map_err(|e| {
-            error!("Failed to start VM with config {:?}: {:?}", config, e);
-            StatusCode::UNKNOWN_ERROR
+            error!("Failed to start VM with config {:?}: {}", config, e);
+            new_binder_exception(
+                ExceptionCode::SERVICE_SPECIFIC,
+                format!("Failed to start VM: {}", e),
+            )
         })?;
         state.add_vm(Arc::downgrade(&instance));
         Ok(VirtualMachine::create(instance))
@@ -139,26 +149,20 @@
         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 size = size.try_into().map_err(|e| {
+            new_binder_exception(
+                ExceptionCode::ILLEGAL_ARGUMENT,
+                format!("Invalid size {}: {}", size, e),
+            )
         })?;
-        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| {
+            new_binder_exception(
+                ExceptionCode::SERVICE_SPECIFIC,
+                format!("Failed to create QCOW2 image: {}", e),
+            )
+        })?;
 
         Ok(())
     }
@@ -166,9 +170,7 @@
     /// 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>> {
-        if !debug_access_allowed() {
-            return Err(StatusCode::PERMISSION_DENIED.into());
-        }
+        check_debug_access()?;
 
         let state = &mut *self.state.lock().unwrap();
         let vms = state.vms();
@@ -189,9 +191,7 @@
     /// Hold a strong reference to a VM in VirtualizationService. This method is only intended for
     /// debug purposes, and as such is only permitted from the shell user.
     fn debugHoldVmRef(&self, vmref: &Strong<dyn IVirtualMachine>) -> binder::Result<()> {
-        if !debug_access_allowed() {
-            return Err(StatusCode::PERMISSION_DENIED.into());
-        }
+        check_debug_access()?;
 
         let state = &mut *self.state.lock().unwrap();
         state.debug_hold_vm(vmref.clone());
@@ -202,9 +202,7 @@
     /// the VM was found and None otherwise. This method is only intended for debug purposes, and as
     /// such is only permitted from the shell user.
     fn debugDropVmRef(&self, cid: i32) -> binder::Result<Option<Strong<dyn IVirtualMachine>>> {
-        if !debug_access_allowed() {
-            return Err(StatusCode::PERMISSION_DENIED.into());
-        }
+        check_debug_access()?;
 
         let state = &mut *self.state.lock().unwrap();
         Ok(state.debug_drop_vm(cid))
@@ -219,19 +217,25 @@
     temporary_directory: &Path,
     next_temporary_image_id: &mut u64,
     indirect_files: &mut Vec<File>,
-) -> Result<DiskFile, StatusCode> {
+) -> Result<DiskFile, Status> {
     let image = if !disk.partitions.is_empty() {
         if disk.image.is_some() {
             warn!("DiskImage {:?} contains both image and partitions.", disk);
-            return Err(StatusCode::BAD_VALUE);
+            return Err(new_binder_exception(
+                ExceptionCode::ILLEGAL_ARGUMENT,
+                "DiskImage contains both image and partitions.",
+            ));
         }
 
         let composite_image_filename =
             make_composite_image_filename(temporary_directory, next_temporary_image_id);
         let (image, partition_files) =
             make_composite_image(&disk.partitions, &composite_image_filename).map_err(|e| {
-                error!("Failed to make composite image with config {:?}: {:?}", disk, e);
-                StatusCode::UNKNOWN_ERROR
+                error!("Failed to make composite image with config {:?}: {}", disk, e);
+                new_binder_exception(
+                    ExceptionCode::SERVICE_SPECIFIC,
+                    format!("Failed to make composite image: {}", e),
+                )
             })?;
 
         // Pass the file descriptors for the various partition files to crosvm when it
@@ -243,7 +247,10 @@
         clone_file(image)?
     } else {
         warn!("DiskImage {:?} didn't contain image or partitions.", disk);
-        return Err(StatusCode::BAD_VALUE);
+        return Err(new_binder_exception(
+            ExceptionCode::ILLEGAL_ARGUMENT,
+            "DiskImage didn't contain image or partitions.",
+        ));
     };
 
     Ok(DiskFile { image, writable: disk.writable })
@@ -260,28 +267,35 @@
 }
 
 /// Gets the calling SID of the current Binder thread.
-fn get_calling_sid() -> Result<String, StatusCode> {
+fn get_calling_sid() -> Result<String, Status> {
     ThreadState::with_calling_sid(|sid| {
         if let Some(sid) = sid {
             match sid.to_str() {
                 Ok(sid) => Ok(sid.to_owned()),
                 Err(e) => {
-                    error!("SID was not valid UTF-8: {:?}", e);
-                    Err(StatusCode::BAD_VALUE)
+                    error!("SID was not valid UTF-8: {}", e);
+                    Err(new_binder_exception(
+                        ExceptionCode::ILLEGAL_ARGUMENT,
+                        format!("SID was not valid UTF-8: {}", e),
+                    ))
                 }
             }
         } else {
             error!("Missing SID on startVm");
-            Err(StatusCode::UNKNOWN_ERROR)
+            Err(new_binder_exception(ExceptionCode::SECURITY, "Missing SID on startVm"))
         }
     })
 }
 
 /// Check whether the caller of the current Binder method is allowed to call debug methods.
-fn debug_access_allowed() -> bool {
+fn check_debug_access() -> binder::Result<()> {
     let uid = ThreadState::get_calling_uid();
     log::trace!("Debug method call from UID {}.", uid);
-    DEBUG_ALLOWED_UIDS.contains(&uid)
+    if DEBUG_ALLOWED_UIDS.contains(&uid) {
+        Ok(())
+    } else {
+        Err(new_binder_exception(ExceptionCode::SECURITY, "Debug access denied"))
+    }
 }
 
 /// Implementation of the AIDL `IVirtualMachine` interface. Used as a handle to a VM.
@@ -396,7 +410,7 @@
     fn allocate_cid(&mut self) -> binder::Result<Cid> {
         // TODO(qwandor): keep track of which CIDs are currently in use so that we can reuse them.
         let cid = self.next_cid;
-        self.next_cid = self.next_cid.checked_add(1).ok_or(StatusCode::UNKNOWN_ERROR)?;
+        self.next_cid = self.next_cid.checked_add(1).ok_or(ExceptionCode::ILLEGAL_STATE)?;
         Ok(cid)
     }
 }
@@ -413,6 +427,16 @@
 }
 
 /// Converts a `&ParcelFileDescriptor` to a `File` by cloning the file.
-fn clone_file(file: &ParcelFileDescriptor) -> Result<File, StatusCode> {
-    file.as_ref().try_clone().map_err(|_| StatusCode::UNKNOWN_ERROR)
+fn clone_file(file: &ParcelFileDescriptor) -> Result<File, Status> {
+    file.as_ref().try_clone().map_err(|e| {
+        new_binder_exception(
+            ExceptionCode::BAD_PARCELABLE,
+            format!("Failed to clone File from ParcelFileDescriptor: {}", e),
+        )
+    })
+}
+
+/// Constructs a new Binder error `Status` with the given `ExceptionCode` and message.
+fn new_binder_exception<T: AsRef<str>>(exception: ExceptionCode, message: T) -> Status {
+    Status::new_exception(exception, CString::new(message.as_ref()).ok().as_deref())
 }
diff --git a/virtualizationservice/src/crosvm.rs b/virtualizationservice/src/crosvm.rs
index 138236c..797011c 100644
--- a/virtualizationservice/src/crosvm.rs
+++ b/virtualizationservice/src/crosvm.rs
@@ -133,7 +133,7 @@
 
         // Delete temporary files.
         if let Err(e) = remove_dir_all(&self.temporary_directory) {
-            error!("Error removing temporary directory {:?}: {:?}", self.temporary_directory, e);
+            error!("Error removing temporary directory {:?}: {}", self.temporary_directory, e);
         }
     }
 
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))?;
diff --git a/zipfuse/zipfuse.rc b/zipfuse/zipfuse.rc
index ccd94b6..1905705 100644
--- a/zipfuse/zipfuse.rc
+++ b/zipfuse/zipfuse.rc
@@ -1,2 +1,2 @@
-service zipfuse /system/bin/zipfuse -o fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0 /dev/block/by-name/microdroid-apk /mnt/apk
+service zipfuse /system/bin/zipfuse -o fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0 /dev/block/mapper/microdroid-apk /mnt/apk
     disabled