Merge "Add AVFHostTestCases to postsubmit and fix boot time is not as expected issue."
diff --git a/apex/Android.bp b/apex/Android.bp
index 923c378..83985cc 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -69,6 +69,9 @@
     ],
     file_contexts: ":com.android.virt-file_contexts",
     canned_fs_config: "canned_fs_config",
+    host_required: [
+        "vm_shell",
+    ],
 }
 
 apex_key {
diff --git a/authfs/fd_server/src/aidl.rs b/authfs/fd_server/src/aidl.rs
index 9a60bf7..0859a7a 100644
--- a/authfs/fd_server/src/aidl.rs
+++ b/authfs/fd_server/src/aidl.rs
@@ -27,11 +27,10 @@
 use std::fs::File;
 use std::io;
 use std::os::unix::fs::FileExt;
-use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd, RawFd};
 use std::path::{Component, Path, PathBuf, MAIN_SEPARATOR};
 use std::sync::{Arc, RwLock};
 
-use crate::common::OwnedFd;
 use crate::fsverity;
 use authfs_aidl_interface::aidl::com::android::virt::fs::IVirtFdService::{
     BnVirtFdService, FsStat::FsStat, IVirtFdService, MAX_REQUESTING_DATA,
diff --git a/authfs/fd_server/src/common.rs b/authfs/fd_server/src/common.rs
deleted file mode 100644
index f836bac..0000000
--- a/authfs/fd_server/src/common.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-
-use std::fs::File;
-use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
-
-// TODO: Remove if/when std::os::unix::io::OwnedFd is standardized.
-pub struct OwnedFd {
-    owner: File,
-}
-
-impl FromRawFd for OwnedFd {
-    unsafe fn from_raw_fd(fd: RawFd) -> Self {
-        OwnedFd { owner: File::from_raw_fd(fd) }
-    }
-}
-
-impl AsRawFd for OwnedFd {
-    fn as_raw_fd(&self) -> RawFd {
-        self.owner.as_raw_fd()
-    }
-}
diff --git a/authfs/fd_server/src/main.rs b/authfs/fd_server/src/main.rs
index 23a76e2..5b7a4f4 100644
--- a/authfs/fd_server/src/main.rs
+++ b/authfs/fd_server/src/main.rs
@@ -23,7 +23,6 @@
 //! client can then request the content of file 9 by offset and size.
 
 mod aidl;
-mod common;
 mod fsverity;
 
 use anyhow::{bail, Result};
diff --git a/microdroid/README.md b/microdroid/README.md
index fef71ce..5cfa523 100644
--- a/microdroid/README.md
+++ b/microdroid/README.md
@@ -167,17 +167,7 @@
 `/apex/com.android.virt/bin/vm run-app` command, and then
 
 ```sh
-adb forward tcp:8000 vsock:$CID:5555
-adb connect localhost:8000
+vm_shell
 ```
 
-`$CID` should be the CID that `vm` reported upon execution of the `vm run`
-command in the above. You can also check it with
-`adb shell "/apex/com.android.virt/bin/vm list"`. `5555` must be the value.
-`8000` however can be any port on the development machine.
-
-Done. Now you can log into microdroid. Have fun!
-
-```sh
-$ adb -s localhost:8000 shell
-```
+Done. Now you are logged into Microdroid. Have fun!
diff --git a/microdroid/kernel/arm64/kernel-5.15 b/microdroid/kernel/arm64/kernel-5.15
index 33c8c13..49b7f69 100644
--- a/microdroid/kernel/arm64/kernel-5.15
+++ b/microdroid/kernel/arm64/kernel-5.15
Binary files differ
diff --git a/tests/Android.bp b/tests/Android.bp
index b849d37..5c1b5c4 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -90,11 +90,3 @@
     ],
     type: "cpio",
 }
-
-genrule {
-    name: "test-payload-metadata",
-    tools: ["mk_payload"],
-    cmd: "$(location mk_payload) --metadata-only $(in) $(out)",
-    srcs: ["test-payload-metadata-config.json"],
-    out: ["test-payload-metadata.img"],
-}
diff --git a/tests/hostside/Android.bp b/tests/hostside/Android.bp
index d77f3de..7679c57 100644
--- a/tests/hostside/Android.bp
+++ b/tests/hostside/Android.bp
@@ -23,7 +23,6 @@
         ":microdroid_general_sepolicy.conf",
         ":test.com.android.virt.pem",
         ":test2.com.android.virt.pem",
-        ":test-payload-metadata",
     ],
     data_native_bins: [
         "sepolicy-analyze",
@@ -32,6 +31,7 @@
         "img2simg",
         "lpmake",
         "lpunpack",
+        "mk_payload",
         "sign_virt_apex",
         "simg2img",
     ],
diff --git a/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java b/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java
index 5ac36a0..c0f293e 100644
--- a/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java
+++ b/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java
@@ -32,6 +32,8 @@
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
+import static java.util.stream.Collectors.toList;
+
 import android.cts.statsdatom.lib.ConfigUtils;
 import android.cts.statsdatom.lib.ReportUtils;
 
@@ -139,6 +141,53 @@
         return new JSONObject(Map.of("label", label, "path", path));
     }
 
+    private void createPayloadMetadata(List<ActiveApexInfo> apexes, File payloadMetadata)
+            throws Exception {
+        // mk_payload's config
+        File configFile = new File(payloadMetadata.getParentFile(), "payload_config.json");
+        JSONObject config = new JSONObject();
+        config.put(
+                "apk",
+                new JSONObject(Map.of("name", "microdroid-apk", "path", "", "idsig_path", "")));
+        config.put("payload_config_path", "/mnt/apk/assets/vm_config.json");
+        config.put(
+                "apexes",
+                new JSONArray(
+                        apexes.stream()
+                                .map(apex -> new JSONObject(Map.of("name", apex.name, "path", "")))
+                                .collect(toList())));
+        FileUtil.writeToFile(config.toString(), configFile);
+
+        File mkPayload = findTestFile("mk_payload");
+        RunUtil runUtil = new RunUtil();
+        // Set the parent dir on the PATH (e.g. <workdir>/bin)
+        String separator = System.getProperty("path.separator");
+        String path = mkPayload.getParentFile().getPath() + separator + System.getenv("PATH");
+        runUtil.setEnvVariable("PATH", path);
+
+        List<String> command = new ArrayList<String>();
+        command.add("mk_payload");
+        command.add("--metadata-only");
+        command.add(configFile.toString());
+        command.add(payloadMetadata.toString());
+
+        CommandResult result =
+                runUtil.runTimedCmd(
+                        // mk_payload should run fast enough
+                        5 * 1000, "/bin/bash", "-c", String.join(" ", command));
+        String out = result.getStdout();
+        String err = result.getStderr();
+        assertWithMessage(
+                        "creating payload metadata failed:\n\tout: "
+                                + out
+                                + "\n\terr: "
+                                + err
+                                + "\n")
+                .about(command_results())
+                .that(result)
+                .isSuccess();
+    }
+
     private void resignVirtApex(File virtApexDir, File signingKey, Map<String, File> keyOverrides) {
         File signVirtApex = findTestFile("sign_virt_apex");
 
@@ -193,10 +242,12 @@
     static class ActiveApexInfo {
         public String name;
         public String path;
+        public boolean provideSharedApexLibs;
 
-        ActiveApexInfo(String name, String path) {
+        ActiveApexInfo(String name, String path, boolean provideSharedApexLibs) {
             this.name = name;
             this.path = path;
+            this.provideSharedApexLibs = provideSharedApexLibs;
         }
     }
 
@@ -215,6 +266,10 @@
             }
             return null;
         }
+
+        List<ActiveApexInfo> getSharedLibApexes() {
+            return mList.stream().filter(info -> info.provideSharedApexLibs).collect(toList());
+        }
     }
 
     private ActiveApexInfoList getActiveApexInfoList() throws Exception {
@@ -229,10 +284,10 @@
                             String uri, String localName, String qName, Attributes attributes) {
                         if (localName.equals("apex-info")
                                 && attributes.getValue("isActive").equals("true")) {
-                            list.add(
-                                    new ActiveApexInfo(
-                                            attributes.getValue("moduleName"),
-                                            attributes.getValue("modulePath")));
+                            String name = attributes.getValue("moduleName");
+                            String path = attributes.getValue("modulePath");
+                            String sharedApex = attributes.getValue("provideSharedApexLibs");
+                            list.add(new ActiveApexInfo(name, path, "true".equals(sharedApex)));
                         }
                     }
                 };
@@ -277,14 +332,11 @@
                 instanceImgPath,
                 Integer.toString(10 * 1024 * 1024));
 
-        // payload-metadata is prepared on host with the two APEXes and APK
+        // payload-metadata is created on device
         final String payloadMetadataPath = TEST_ROOT + "payload-metadata.img";
-        getDevice().pushFile(findTestFile("test-payload-metadata.img"), payloadMetadataPath);
 
-        // get paths to the two APEXes required for the VM.
+        // Load /apex/apex-info-list.xml to get paths to APEXes required for the VM.
         ActiveApexInfoList list = getActiveApexInfoList();
-        final String statsdApexPath = list.get("com.android.os.statsd").path;
-        final String adbdApexPath = list.get("com.android.adbd").path;
 
         // Since Java APP can't start a VM with a custom image, here, we start a VM using `vm run`
         // command with a VM Raw config which is equiv. to what virtualizationservice creates with
@@ -325,19 +377,26 @@
 
         // Add payload image disk with partitions:
         // - payload-metadata
-        // - apexes: com.android.os.statsd, com.android.adbd
+        // - apexes: com.android.os.statsd, com.android.adbd, [sharedlib apex](optional)
         // - apk and idsig
-        disks.put(
-                new JSONObject()
-                        .put("writable", false)
-                        .put(
-                                "partitions",
-                                new JSONArray()
-                                        .put(newPartition("payload-metadata", payloadMetadataPath))
-                                        .put(newPartition("com.android.os.statsd", statsdApexPath))
-                                        .put(newPartition("com.android.adbd", adbdApexPath))
-                                        .put(newPartition("microdroid-apk", apkPath))
-                                        .put(newPartition("microdroid-apk-idsig", idSigPath))));
+        List<ActiveApexInfo> apexesForVm = new ArrayList<>();
+        apexesForVm.add(list.get("com.android.os.statsd"));
+        apexesForVm.add(list.get("com.android.adbd"));
+        apexesForVm.addAll(list.getSharedLibApexes());
+
+        final JSONArray partitions = new JSONArray();
+        partitions.put(newPartition("payload-metadata", payloadMetadataPath));
+        for (ActiveApexInfo apex : apexesForVm) {
+            partitions.put(newPartition(apex.name, apex.path));
+        }
+        partitions
+                .put(newPartition("microdroid-apk", apkPath))
+                .put(newPartition("microdroid-apk-idsig", idSigPath));
+        disks.put(new JSONObject().put("writable", false).put("partitions", partitions));
+
+        final File localPayloadMetadata = new File(virtApexDir, "payload-metadata.img");
+        createPayloadMetadata(apexesForVm, localPayloadMetadata);
+        getDevice().pushFile(localPayloadMetadata, payloadMetadataPath);
 
         config.put("protected", isProtected);
 
diff --git a/tests/test-payload-metadata-config.json b/tests/test-payload-metadata-config.json
deleted file mode 100644
index 3c56e5f..0000000
--- a/tests/test-payload-metadata-config.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-  "_comment": "This file is to create a payload-metadata partition for payload.img which is for MicrodroidTestApp to run with assets/vm_config.json",
-  "apexes": [
-    {
-      "name": "com.android.os.statsd",
-      "path": ""
-    },
-    {
-      "name": "com.android.adbd",
-      "path": ""
-    }
-  ],
-  "apk": {
-    "name": "microdroid-apk",
-    "path": "",
-    "idsig_path": ""
-  },
-  "payload_config_path": "/mnt/apk/assets/vm_config.json"
-}
\ No newline at end of file
diff --git a/vm/Android.bp b/vm/Android.bp
index f9eac4d..2e914c4 100644
--- a/vm/Android.bp
+++ b/vm/Android.bp
@@ -28,3 +28,8 @@
         "com.android.virt",
     ],
 }
+
+sh_binary_host {
+    name: "vm_shell",
+    src: "vm_shell.sh",
+}
diff --git a/vm/vm_shell.sh b/vm/vm_shell.sh
new file mode 100755
index 0000000..ec9243b
--- /dev/null
+++ b/vm/vm_shell.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+
+# Copyright 2020 Google Inc. All rights reserved.
+#
+# 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.
+
+# vm_shell.sh shows the VMs running in the Android device and connects to it
+# Usage:
+# vm_shell [cid]
+#
+#   cid: CID of the VM to connect to. If omitted, the list of CIDs available are shown
+
+function connect_vm() {
+    cid=$1
+    echo Connecting to CID ${cid}
+    adb disconnect localhost:8000
+    adb forward tcp:8000 vsock:${cid}:5555
+    adb connect localhost:8000
+    adb -s localhost:8000 root
+    sleep 2
+    adb -s localhost:8000 shell
+    exit 0
+}
+
+selected_cid=$1
+available_cids=$(adb shell /apex/com.android.virt/bin/vm list | awk 'BEGIN { FS="[:,]" } /cid/ { print $2; }')
+
+if [ -z "${available_cids}" ]; then
+    echo No VM is available
+    exit 1
+fi
+
+if [ -n "${selected_cid}" ]; then
+    if [[ ! " ${available_cids[*]} " =~ " ${selected_cid} " ]]; then
+        echo VM of CID $selected_cid does not exist. Available CIDs: ${available_cids}
+        exit 1
+    fi
+else
+    PS3="Select CID of VM to adb-shell into: "
+    select cid in ${available_cids}
+    do
+        selected_cid=${cid}
+        break
+    done
+fi
+
+connect_vm ${selected_cid}