Merge "Add --prefer-staged to composd_cmd test-compile"
diff --git a/authfs/src/fusefs/mount.rs b/authfs/src/fusefs/mount.rs
index e7f8c94..294c6b1 100644
--- a/authfs/src/fusefs/mount.rs
+++ b/authfs/src/fusefs/mount.rs
@@ -53,8 +53,13 @@
         mount_options.push(MountOption::Extra(value));
     }
 
-    fuse::mount(mountpoint, "authfs", libc::MS_NOSUID | libc::MS_NODEV, &mount_options)
-        .expect("Failed to mount fuse");
+    fuse::mount(
+        mountpoint,
+        "authfs",
+        libc::MS_NOSUID | libc::MS_NODEV | libc::MS_NOEXEC,
+        &mount_options,
+    )
+    .expect("Failed to mount fuse");
 
     fuse::worker::start_message_loop(dev_fuse, MAX_WRITE_BYTES, MAX_READ_BYTES, authfs)
 }
diff --git a/compos/verify/verify.rs b/compos/verify/verify.rs
index 55fe1bd..184b9ff 100644
--- a/compos/verify/verify.rs
+++ b/compos/verify/verify.rs
@@ -17,6 +17,7 @@
 //! A tool to verify a CompOS signature. It starts a CompOS VM as part of this to retrieve the
 //!  public key. The tool is intended to be run by odsign during boot.
 
+use android_logger::LogId;
 use anyhow::{bail, Context, Result};
 use compos_aidl_interface::binder::ProcessState;
 use compos_common::compos_client::{VmInstance, VmParameters};
@@ -39,7 +40,8 @@
     android_logger::init_once(
         android_logger::Config::default()
             .with_tag("compos_verify")
-            .with_min_level(log::Level::Info),
+            .with_min_level(log::Level::Info)
+            .with_log_id(LogId::System), // Needed to log successfully early in boot
     );
 
     // Redirect panic messages to logcat.
diff --git a/tests/hostside/helper/Android.bp b/tests/hostside/helper/Android.bp
index aa748ab..4ca0bf0 100644
--- a/tests/hostside/helper/Android.bp
+++ b/tests/hostside/helper/Android.bp
@@ -2,12 +2,9 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-java_test_helper_library {
+java_library_host {
     name: "VirtualizationTestHelper",
-    host_supported: true,
-    device_supported: false,
     srcs: ["java/**/*.java"],
-    test_suites: ["general-tests"],
     libs: [
         "tradefed",
         "compatibility-tradefed",
diff --git a/tests/hostside/helper/java/android/virt/test/VirtualizationTestCaseBase.java b/tests/hostside/helper/java/android/virt/test/VirtualizationTestCaseBase.java
index e45e524..0f6204c 100644
--- a/tests/hostside/helper/java/android/virt/test/VirtualizationTestCaseBase.java
+++ b/tests/hostside/helper/java/android/virt/test/VirtualizationTestCaseBase.java
@@ -194,6 +194,22 @@
         }
     }
 
+    public String getPathForPackage(String packageName)
+            throws DeviceNotAvailableException {
+        return getPathForPackage(getDevice(), packageName);
+    }
+
+    // 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.
+    private static String getPathForPackage(ITestDevice device, String packageName)
+            throws DeviceNotAvailableException {
+        CommandRunner android = new CommandRunner(device);
+        String pathLine = android.run("pm", "path", packageName);
+        assertTrue("package not found", pathLine.startsWith("package:"));
+        return pathLine.substring("package:".length());
+    }
+
     public static String startMicrodroid(
             ITestDevice androidDevice,
             IBuildInfo buildInfo,
@@ -247,13 +263,8 @@
             androidDevice.installPackage(apkFile, /* reinstall */ true);
         }
 
-        // 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.
         if (apkPath == null) {
-            apkPath = android.run("pm", "path", packageName);
-            assertTrue(apkPath.startsWith("package:"));
-            apkPath = apkPath.substring("package:".length());
+            apkPath = getPathForPackage(androidDevice, packageName);
         }
 
         android.run("mkdir", "-p", TEST_ROOT);
diff --git a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
index d0bc91a..e65459a 100644
--- a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
+++ b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
@@ -143,14 +143,6 @@
         boolean writable;
     }
 
-    private String getPathForPackage(String packageName)
-            throws DeviceNotAvailableException {
-        CommandRunner android = new CommandRunner(getDevice());
-        String pathLine = android.run("pm", "path", packageName);
-        assertTrue("package not found", pathLine.startsWith("package:"));
-        return pathLine.substring("package:".length());
-    }
-
     private void resignVirtApex(File virtApexDir, File signingKey) {
         File signVirtApex = findTestFile("sign_virt_apex");
 
diff --git a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
index cd9f284..27e1846 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -73,9 +73,20 @@
     private static final String KERNEL_VERSION = SystemProperties.get("ro.kernel.version");
 
     private static class Inner {
+        public boolean mProtectedVm;
         public Context mContext;
         public VirtualMachineManager mVmm;
         public VirtualMachine mVm;
+
+        Inner(boolean protectedVm) {
+            mProtectedVm = protectedVm;
+        }
+
+        /** Create a new VirtualMachineConfig.Builder with the parameterized protection mode. */
+        public VirtualMachineConfig.Builder newVmConfigBuilder(String payloadConfigPath) {
+            return new VirtualMachineConfig.Builder(mContext, payloadConfigPath)
+                            .protectedVm(mProtectedVm);
+        }
     }
 
     @Parameterized.Parameters(name = "protectedVm={0}")
@@ -112,7 +123,7 @@
                 .that(HypervisorProperties.hypervisor_vm_supported().orElse(false))
                 .isTrue();
         }
-        mInner = new Inner();
+        mInner = new Inner(mProtectedVm);
         mInner.mContext = ApplicationProvider.getApplicationContext();
         mInner.mVmm = VirtualMachineManager.getInstance(mInner.mContext);
     }
@@ -181,8 +192,7 @@
             .isNotEqualTo("5.4");
 
         VirtualMachineConfig.Builder builder =
-                new VirtualMachineConfig.Builder(mInner.mContext, "assets/vm_config_extra_apk.json")
-                        .protectedVm(mProtectedVm);
+                mInner.newVmConfigBuilder("assets/vm_config_extra_apk.json");
         if (Build.SUPPORTED_ABIS.length > 0) {
             String primaryAbi = Build.SUPPORTED_ABIS[0];
             switch(primaryAbi) {
@@ -261,9 +271,7 @@
             .that(KERNEL_VERSION)
             .isNotEqualTo("5.4");
 
-        VirtualMachineConfig.Builder builder =
-                new VirtualMachineConfig.Builder(mInner.mContext, "assets/vm_config.json")
-                        .protectedVm(mProtectedVm);
+        VirtualMachineConfig.Builder builder = mInner.newVmConfigBuilder("assets/vm_config.json");
         VirtualMachineConfig normalConfig = builder.debugLevel(DebugLevel.NONE).build();
         mInner.mVm = mInner.mVmm.getOrCreate("test_vm", normalConfig);
         VmEventListener listener =
@@ -306,10 +314,9 @@
 
     private VmCdis launchVmAndGetCdis(String instanceName)
             throws VirtualMachineException, InterruptedException {
-        VirtualMachineConfig.Builder builder =
-                new VirtualMachineConfig.Builder(mInner.mContext, "assets/vm_config.json")
-                        .protectedVm(mProtectedVm);
-        VirtualMachineConfig normalConfig = builder.debugLevel(DebugLevel.NONE).build();
+        VirtualMachineConfig normalConfig = mInner.newVmConfigBuilder("assets/vm_config.json")
+                .debugLevel(DebugLevel.NONE)
+                .build();
         mInner.mVm = mInner.mVmm.getOrCreate(instanceName, normalConfig);
         final VmCdis vmCdis = new VmCdis();
         final CompletableFuture<Exception> exception = new CompletableFuture<>();
@@ -391,10 +398,9 @@
             .that(KERNEL_VERSION)
             .isNotEqualTo("5.4");
 
-        VirtualMachineConfig.Builder builder =
-                new VirtualMachineConfig.Builder(mInner.mContext, "assets/vm_config.json")
-                        .protectedVm(mProtectedVm);
-        VirtualMachineConfig normalConfig = builder.debugLevel(DebugLevel.NONE).build();
+        VirtualMachineConfig normalConfig = mInner.newVmConfigBuilder("assets/vm_config.json")
+                .debugLevel(DebugLevel.NONE)
+                .build();
         mInner.mVm = mInner.mVmm.getOrCreate("bcc_vm", normalConfig);
         final VmCdis vmCdis = new VmCdis();
         final CompletableFuture<byte[]> bcc = new CompletableFuture<>();
@@ -433,6 +439,10 @@
 
     private static final UUID MICRODROID_PARTITION_UUID =
             UUID.fromString("cf9afe9a-0662-11ec-a329-c32663a09d75");
+    private static final UUID U_BOOT_AVB_PARTITION_UUID =
+            UUID.fromString("7e8221e7-03e6-4969-948b-73a4c809a4f2");
+    private static final UUID U_BOOT_ENV_PARTITION_UUID =
+            UUID.fromString("0ab72d30-86ae-4d05-81b2-c1760be2b1f9");
     private static final long BLOCK_SIZE = 512;
 
     // Find the starting offset which holds the data of a partition having UUID.
@@ -460,53 +470,11 @@
         file.writeByte(b ^ 1);
     }
 
-    @Test
-    public void bootFailsWhenInstanceDiskIsCompromised()
-            throws VirtualMachineException, InterruptedException, IOException {
-        assume().withMessage("Skip on Cuttlefish. b/195765441")
-                .that(android.os.Build.DEVICE)
-                .isNotEqualTo("vsoc_x86_64");
-
-        VirtualMachineConfig config =
-                new VirtualMachineConfig.Builder(mInner.mContext, "assets/vm_config.json")
-                        .protectedVm(mProtectedVm)
-                        .debugLevel(DebugLevel.NONE)
-                        .build();
-
-        // Remove any existing VM so we can start from scratch
-        VirtualMachine oldVm = mInner.mVmm.getOrCreate("test_vm_integrity", config);
-        oldVm.delete();
-
-        mInner.mVm = mInner.mVmm.getOrCreate("test_vm_integrity", config);
-
-        final CompletableFuture<Boolean> payloadReady = new CompletableFuture<>();
-        VmEventListener listener =
-                new VmEventListener() {
-                    @Override
-                    public void onPayloadReady(VirtualMachine vm) {
-                        payloadReady.complete(true);
-                        forceStop(vm);
-                    }
-                };
-        listener.runToFinish(mInner.mVm);
-        assertThat(payloadReady.getNow(false)).isTrue();
-
-        // Launch the same VM after flipping a bit of the instance image.
-        // Flip actual data, as flipping trivial bits like the magic string isn't interesting.
-        File vmRoot = new File(mInner.mContext.getFilesDir(), "vm");
-        File vmDir = new File(vmRoot, "test_vm_integrity");
-        File instanceImgPath = new File(vmDir, "instance.img");
-        RandomAccessFile instanceFile = new RandomAccessFile(instanceImgPath, "rw");
-
-        // microdroid data partition must exist.
-        OptionalLong microdroidPartitionOffset =
-                findPartitionDataOffset(instanceFile, MICRODROID_PARTITION_UUID);
-        assertThat(microdroidPartitionOffset.isPresent()).isTrue();
-
-        flipBit(instanceFile, microdroidPartitionOffset.getAsLong());
-        mInner.mVm = mInner.mVmm.get("test_vm_integrity"); // re-load the vm with new instance disk
+    private boolean tryBootVm(String vmName)
+            throws VirtualMachineException, InterruptedException {
+        mInner.mVm = mInner.mVmm.get(vmName); // re-load the vm before running tests
         final CompletableFuture<Boolean> payloadStarted = new CompletableFuture<>();
-        listener =
+        VmEventListener listener =
                 new VmEventListener() {
                     @Override
                     public void onPayloadStarted(VirtualMachine vm, ParcelFileDescriptor stream) {
@@ -515,7 +483,45 @@
                     }
                 };
         listener.runToFinish(mInner.mVm);
-        assertThat(payloadStarted.getNow(false)).isFalse();
-        flipBit(instanceFile, microdroidPartitionOffset.getAsLong());
+        return payloadStarted.getNow(false);
+    }
+
+    @Test
+    public void bootFailsWhenInstanceDiskIsCompromised()
+            throws VirtualMachineException, InterruptedException, IOException {
+        assume().withMessage("Skip on Cuttlefish. b/195765441")
+                .that(android.os.Build.DEVICE)
+                .isNotEqualTo("vsoc_x86_64");
+
+        VirtualMachineConfig config = mInner.newVmConfigBuilder("assets/vm_config.json")
+                .debugLevel(DebugLevel.NONE)
+                .build();
+
+        // Remove any existing VM so we can start from scratch
+        VirtualMachine oldVm = mInner.mVmm.getOrCreate("test_vm_integrity", config);
+        oldVm.delete();
+        mInner.mVmm.getOrCreate("test_vm_integrity", config);
+
+        assertThat(tryBootVm("test_vm_integrity")).isTrue();
+
+        // Launch the same VM after flipping a bit of the instance image.
+        // Flip actual data, as flipping trivial bits like the magic string isn't interesting.
+        File vmRoot = new File(mInner.mContext.getFilesDir(), "vm");
+        File vmDir = new File(vmRoot, "test_vm_integrity");
+        File instanceImgPath = new File(vmDir, "instance.img");
+        RandomAccessFile instanceFile = new RandomAccessFile(instanceImgPath, "rw");
+
+        // partitions may or may not exist
+        for (UUID uuid :
+                new UUID[] {
+                    MICRODROID_PARTITION_UUID, U_BOOT_AVB_PARTITION_UUID, U_BOOT_ENV_PARTITION_UUID
+                }) {
+            OptionalLong offset = findPartitionDataOffset(instanceFile, uuid);
+            if (!offset.isPresent()) continue;
+
+            flipBit(instanceFile, offset.getAsLong());
+            assertThat(tryBootVm("test_vm_integrity")).isFalse();
+            flipBit(instanceFile, offset.getAsLong());
+        }
     }
 }