Merge changes from topics "b/186126194", "b/199367367"

* changes:
  Create composd skeleton
  Register as a lazy service.
diff --git a/apkverify/src/lib.rs b/apkverify/src/lib.rs
index f75913c..71ea857 100644
--- a/apkverify/src/lib.rs
+++ b/apkverify/src/lib.rs
@@ -26,8 +26,14 @@
 use anyhow::Result;
 use std::path::Path;
 
-/// Verifies APK/APEX signing with v2/v3 scheme
-pub fn verify<P: AsRef<Path>>(path: P) -> Result<()> {
+/// Verifies APK/APEX signing with v2/v3 scheme. On success, the public key (in DER format) is
+/// returned.
+pub fn verify<P: AsRef<Path>>(path: P) -> Result<Box<[u8]>> {
     // TODO(jooyung) fallback to v2 when v3 not found
     v3::verify(path)
 }
+
+/// Gets the public key (in DER format) that was used to sign the given APK/APEX file
+pub fn get_public_key_der<P: AsRef<Path>>(path: P) -> Result<Box<[u8]>> {
+    v3::get_public_key_der(path)
+}
diff --git a/apkverify/src/v3.rs b/apkverify/src/v3.rs
index 2f9ce94..797911b 100644
--- a/apkverify/src/v3.rs
+++ b/apkverify/src/v3.rs
@@ -86,40 +86,50 @@
 type X509Certificate = Bytes;
 type AdditionalAttributes = Bytes;
 
-/// Verifies APK Signature Scheme v3 signatures of the provided APK and returns the certificates
-/// associated with each signer.
-pub fn verify<P: AsRef<Path>>(path: P) -> Result<()> {
+/// Verifies APK Signature Scheme v3 signatures of the provided APK and returns the public key
+/// associated with the signer.
+pub fn verify<P: AsRef<Path>>(path: P) -> Result<Box<[u8]>> {
     let f = File::open(path.as_ref())?;
     let mut sections = ApkSections::new(f)?;
-    verify_signature(&mut sections)?;
-    Ok(())
+    find_signer_and_then(&mut sections, |(signer, sections)| signer.verify(sections))
 }
 
-/// Verifies the contents of the provided APK file against the provided APK Signature Scheme v3
-/// Block.
-fn verify_signature<R: Read + Seek>(sections: &mut ApkSections<R>) -> Result<()> {
+/// Finds the supported signer and execute a function on it.
+fn find_signer_and_then<R, U, F>(sections: &mut ApkSections<R>, f: F) -> Result<U>
+where
+    R: Read + Seek,
+    F: FnOnce((&Signer, &mut ApkSections<R>)) -> Result<U>,
+{
     let mut block = sections.find_signature(APK_SIGNATURE_SCHEME_V3_BLOCK_ID)?;
-
     // parse v3 scheme block
     let signers = block.read::<Signers>()?;
 
     // find supported by platform
-    let mut supported =
-        signers.iter().filter(|s| s.sdk_range().contains(&SDK_INT)).collect::<Vec<_>>();
+    let supported = signers.iter().filter(|s| s.sdk_range().contains(&SDK_INT)).collect::<Vec<_>>();
 
     // there should be exactly one
     if supported.len() != 1 {
-        bail!("APK Signature Scheme V3 only supports one signer: {} signers found.", signers.len())
+        bail!(
+            "APK Signature Scheme V3 only supports one signer: {} signers found.",
+            supported.len()
+        )
     }
 
-    // and it should be verified
-    supported.pop().unwrap().verify(sections)?;
+    // Call the supplied function
+    f((supported[0], sections))
+}
 
-    Ok(())
+/// Gets the public key (in DER format) that was used to sign the given APK/APEX file
+pub fn get_public_key_der<P: AsRef<Path>>(path: P) -> Result<Box<[u8]>> {
+    let f = File::open(path.as_ref())?;
+    let mut sections = ApkSections::new(f)?;
+    find_signer_and_then(&mut sections, |(signer, _)| {
+        Ok(signer.public_key.to_vec().into_boxed_slice())
+    })
 }
 
 impl Signer {
-    fn verify<R: Read + Seek>(&self, sections: &mut ApkSections<R>) -> Result<()> {
+    fn verify<R: Read + Seek>(&self, sections: &mut ApkSections<R>) -> Result<Box<[u8]>> {
         // 1. Choose the strongest supported signature algorithm ID from signatures. The strength
         //    ordering is up to each implementation/platform version.
         let strongest: &Signature = self
@@ -181,7 +191,7 @@
         }
 
         // TODO(jooyung) 8. If the proof-of-rotation attribute exists for the signer verify that the struct is valid and this signer is the last certificate in the list.
-        Ok(())
+        Ok(self.public_key.to_vec().into_boxed_slice())
     }
 }
 
diff --git a/microdroid/init.rc b/microdroid/init.rc
index 347f514..23434bb 100644
--- a/microdroid/init.rc
+++ b/microdroid/init.rc
@@ -18,12 +18,11 @@
     start ueventd
 
     mkdir /mnt/apk 0755 system system
+    # Microdroid_manager starts apkdmverity/zipfuse/apexd
     start microdroid_manager
 
-    # Exec apexd in the VM mode to avoid unnecessary overhead of normal mode.
-    # (e.g. session management)
-    exec - root system -- /system/bin/apexd --vm
-
+    # Wait for apexd to finish activating APEXes before starting more processes.
+    wait_for_prop apexd.status activated
     perform_apex_config
 
     # Notify to microdroid_manager that perform_apex_config is done.
@@ -170,6 +169,12 @@
     mkdir /data/local 0751 root root
     mkdir /data/local/tmp 0771 shell shell
 
+service apexd-vm /system/bin/apexd --vm
+    user root
+    group system
+    oneshot
+    disabled
+
 service ueventd /system/bin/ueventd
     class core
     critical
diff --git a/microdroid/payload/metadata.proto b/microdroid/payload/metadata.proto
index 0fa0650..4c32dde 100644
--- a/microdroid/payload/metadata.proto
+++ b/microdroid/payload/metadata.proto
@@ -38,11 +38,7 @@
 
   // Optional.
   // When specified, the public key used to sign the apex should match with it.
-  string publicKey = 3;
-
-  // Optional.
-  // When specified, the root digest of the apex should match with it.
-  string rootDigest = 4;
+  bytes public_key = 3;
 }
 
 message ApkPayload {
diff --git a/microdroid/uboot-env-x86_64.txt b/microdroid/uboot-env-x86_64.txt
index fabe5b4..0064cac 100644
--- a/microdroid/uboot-env-x86_64.txt
+++ b/microdroid/uboot-env-x86_64.txt
@@ -3,7 +3,7 @@
 # Boot the device following the Android boot procedure
 # `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 && env set bootargs "$bootargs $avb_bootargs" && boot_android virtio 0 a
+bootcmd=verified_boot_android virtio 0 a
 
 bootdelay=0
 
diff --git a/microdroid/uboot-env.txt b/microdroid/uboot-env.txt
index 2c5bee7..b5f3968 100644
--- a/microdroid/uboot-env.txt
+++ b/microdroid/uboot-env.txt
@@ -3,7 +3,7 @@
 # Boot the device following the Android boot procedure
 # `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 && env set bootargs "$bootargs $avb_bootargs" && boot_android virtio 0 a
+bootcmd=verified_boot_android virtio 0 a
 
 bootdelay=0
 fdtaddr=0x80000000
diff --git a/microdroid_manager/src/instance.rs b/microdroid_manager/src/instance.rs
index 73983a7..e431f51 100644
--- a/microdroid_manager/src/instance.rs
+++ b/microdroid_manager/src/instance.rs
@@ -320,7 +320,7 @@
 #[derive(Debug, Serialize, Deserialize, PartialEq)]
 pub struct ApkData {
     pub root_hash: Box<RootHash>,
-    // TODO(b/199143508) add cert
+    pub pubkey: Box<[u8]>,
 }
 
 pub type RootHash = [u8];
diff --git a/microdroid_manager/src/ioutil.rs b/microdroid_manager/src/ioutil.rs
index e8732ad..ab82e05 100644
--- a/microdroid_manager/src/ioutil.rs
+++ b/microdroid_manager/src/ioutil.rs
@@ -14,6 +14,7 @@
 
 //! IO utilities
 
+use anyhow::{anyhow, Result};
 use std::fs::File;
 use std::io;
 use std::path::Path;
@@ -23,17 +24,17 @@
 const SLEEP_DURATION: Duration = Duration::from_millis(5);
 
 /// waits for a file with a timeout and returns it
-pub fn wait_for_file<P: AsRef<Path>>(path: P, timeout: Duration) -> io::Result<File> {
+pub fn wait_for_file<P: AsRef<Path>>(path: P, timeout: Duration) -> Result<File> {
     let begin = Instant::now();
     loop {
         match File::open(&path) {
             Ok(file) => return Ok(file),
             Err(error) => {
                 if error.kind() != io::ErrorKind::NotFound {
-                    return Err(error);
+                    return Err(anyhow!(error));
                 }
                 if begin.elapsed() > timeout {
-                    return Err(io::Error::from(io::ErrorKind::NotFound));
+                    return Err(anyhow!(io::Error::from(io::ErrorKind::NotFound)));
                 }
                 thread::sleep(SLEEP_DURATION);
             }
@@ -47,7 +48,7 @@
     use std::io::{Read, Write};
 
     #[test]
-    fn test_wait_for_file() -> io::Result<()> {
+    fn test_wait_for_file() -> Result<()> {
         let test_dir = tempfile::TempDir::new().unwrap();
         let test_file = test_dir.path().join("test.txt");
         thread::spawn(move || -> io::Result<()> {
@@ -69,6 +70,9 @@
         let test_file = test_dir.path().join("test.txt");
         let file = wait_for_file(&test_file, Duration::from_secs(1));
         assert!(file.is_err());
-        assert_eq!(io::ErrorKind::NotFound, file.unwrap_err().kind());
+        assert_eq!(
+            io::ErrorKind::NotFound,
+            file.unwrap_err().root_cause().downcast_ref::<io::Error>().unwrap().kind()
+        );
     }
 }
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 2e80b90..ac7adc9 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -19,16 +19,16 @@
 mod payload;
 
 use crate::instance::{ApkData, InstanceDisk, MicrodroidData, RootHash};
-use anyhow::{anyhow, bail, Context, Result};
-use apkverify::verify;
+use anyhow::{anyhow, bail, ensure, Context, Result};
+use apkverify::{get_public_key_der, verify};
 use binder::unstable_api::{new_spibinder, AIBinder};
 use binder::{FromIBinder, Strong};
 use idsig::V4Signature;
 use log::{error, info, warn};
-use microdroid_metadata::Metadata;
+use microdroid_metadata::{write_metadata, Metadata};
 use microdroid_payload_config::{Task, TaskType, VmPayloadConfig};
 use nix::ioctl_read_bad;
-use payload::{get_apex_data_from_payload, load_metadata};
+use payload::{get_apex_data_from_payload, load_metadata, to_metadata};
 use rustutils::system_properties;
 use rustutils::system_properties::PropertyWatcher;
 use std::fs::{self, File, OpenOptions};
@@ -111,13 +111,11 @@
         instance.write_microdroid_data(&verified_data).context("Failed to write identity data")?;
     }
 
-    wait_for_apex_config_done()?;
+    // Before reading a file from the APK, start zipfuse
+    system_properties::write("ctl.start", "zipfuse")?;
 
     let service = get_vms_rpc_binder().expect("cannot connect to VirtualMachineService");
     if !metadata.payload_config_path.is_empty() {
-        // Before reading a file from the APK, start zipfuse
-        system_properties::write("ctl.start", "zipfuse")?;
-
         let config = load_config(Path::new(&metadata.payload_config_path))?;
 
         let fake_secret = "This is a placeholder for a value that is derived from the images that are loaded in the VM.";
@@ -125,7 +123,10 @@
             warn!("failed to set ro.vmsecret.keymint: {}", err);
         }
 
+        // Wait until apex config is done. (e.g. linker configuration for apexes)
         // TODO(jooyung): wait until sys.boot_completed?
+        wait_for_apex_config_done()?;
+
         if let Some(main_task) = &config.task {
             exec_task(main_task, &service).map_err(|e| {
                 error!("failed to execute task: {}", e);
@@ -161,9 +162,23 @@
     // Start apkdmverity and wait for the dm-verify block
     system_properties::write("ctl.start", "apkdmverity")?;
 
-    // While waiting for apkdmverity to mount APK, gathers APEX pubkeys used by APEXd.
-    // These will be compared ones from instance.img.
+    // While waiting for apkdmverity to mount APK, gathers APEX pubkeys from payload.
     let apex_data_from_payload = get_apex_data_from_payload(metadata)?;
+    if let Some(saved_data) = saved_data.map(|d| &d.apex_data) {
+        // For APEX payload, we don't support updating their pubkeys
+        ensure!(saved_data == &apex_data_from_payload, "APEX payloads has changed.");
+        let apex_metadata = to_metadata(&apex_data_from_payload);
+        // Pass metadata(with pubkeys) to apexd so that it uses the passed metadata
+        // instead of the default one (/dev/block/by-name/payload-metadata)
+        OpenOptions::new()
+            .create_new(true)
+            .write(true)
+            .open("/apex/vm-payload-metadata")
+            .context("Failed to open /apex/vm-payload-metadata")
+            .and_then(|f| write_metadata(&apex_metadata, f))?;
+    }
+    // Start apexd to activate APEXes
+    system_properties::write("ctl.start", "apexd-vm")?;
 
     ioutil::wait_for_file(DM_MOUNTED_APK_PATH, WAIT_TIMEOUT)?;
 
@@ -172,16 +187,18 @@
     // taken only when the root_hash is un-trustful which can be either when this is the first boot
     // of the VM or APK was updated in the host.
     // TODO(jooyung): consider multithreading to make this faster
-    if !root_hash_trustful {
-        verify(DM_MOUNTED_APK_PATH).context(format!("failed to verify {}", DM_MOUNTED_APK_PATH))?;
-    }
+    let apk_pubkey = if !root_hash_trustful {
+        verify(DM_MOUNTED_APK_PATH).context(format!("failed to verify {}", DM_MOUNTED_APK_PATH))?
+    } else {
+        get_public_key_der(DM_MOUNTED_APK_PATH)?
+    };
 
     info!("payload verification successful. took {:#?}", start_time.elapsed().unwrap());
 
     // At this point, we can ensure that the root_hash from the idsig file is trusted, either by
     // fully verifying the APK or by comparing it with the saved root_hash.
     Ok(MicrodroidData {
-        apk_data: ApkData { root_hash: root_hash_from_idsig },
+        apk_data: ApkData { root_hash: root_hash_from_idsig, pubkey: apk_pubkey },
         apex_data: apex_data_from_payload,
     })
 }
diff --git a/microdroid_manager/src/payload.rs b/microdroid_manager/src/payload.rs
index bfc6c09..bf9d9f9 100644
--- a/microdroid_manager/src/payload.rs
+++ b/microdroid_manager/src/payload.rs
@@ -18,7 +18,7 @@
 use crate::ioutil::wait_for_file;
 use anyhow::Result;
 use log::info;
-use microdroid_metadata::{read_metadata, Metadata};
+use microdroid_metadata::{read_metadata, ApexPayload, Metadata};
 use std::fs::File;
 use std::io::Read;
 use std::time::Duration;
@@ -35,9 +35,9 @@
     read_metadata(file)
 }
 
-/// Loads (name, pubkey) from payload apexes and returns them as sorted by name.
+/// Loads (name, pubkey) from payload APEXes
 pub fn get_apex_data_from_payload(metadata: &Metadata) -> Result<Vec<ApexData>> {
-    let mut apex_data: Vec<ApexData> = metadata
+    metadata
         .apexes
         .iter()
         .map(|apex| {
@@ -46,9 +46,7 @@
             let pubkey = get_pubkey_from_apex(&partition)?;
             Ok(ApexData { name, pubkey })
         })
-        .collect::<Result<Vec<_>>>()?;
-    apex_data.sort_by(|a, b| a.name.cmp(&b.name));
-    Ok(apex_data)
+        .collect()
 }
 
 fn get_pubkey_from_apex(path: &str) -> Result<Vec<u8>> {
@@ -59,3 +57,18 @@
     pubkey_file.read_to_end(&mut pubkey)?;
     Ok(pubkey)
 }
+
+/// Convert vector of ApexData into Metadata
+pub fn to_metadata(apex_data: &[ApexData]) -> Metadata {
+    Metadata {
+        apexes: apex_data
+            .iter()
+            .map(|data| ApexPayload {
+                name: data.name.clone(),
+                public_key: data.pubkey.clone(),
+                ..Default::default()
+            })
+            .collect(),
+        ..Default::default()
+    }
+}
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 78a70d7..449103e 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -349,7 +349,7 @@
             let port = addr.port();
             info!("payload stream connected from cid={}, port={}", cid, port);
             if let Some(vm) = state.lock().unwrap().get_vm(cid) {
-                vm.stream.lock().unwrap().insert(stream);
+                *vm.stream.lock().unwrap() = Some(stream);
             } else {
                 error!("connection from cid={} is not from a guest VM", cid);
             }
diff --git a/zipfuse/Android.bp b/zipfuse/Android.bp
index 46f4b5a..79e6bad 100644
--- a/zipfuse/Android.bp
+++ b/zipfuse/Android.bp
@@ -29,6 +29,7 @@
     name: "zipfuse",
     defaults: ["zipfuse.defaults"],
     init_rc: ["zipfuse.rc"],
+    bootstrap: true,
 }
 
 rust_test {