Merge changes I9f3a829c,I4404240c

* changes:
  Ignore debug policy with sysprop
  Refactor to handle log output outside of pvmfw
diff --git a/authfs/Android.bp b/authfs/Android.bp
index 154a1d6..2532026 100644
--- a/authfs/Android.bp
+++ b/authfs/Android.bp
@@ -23,7 +23,7 @@
         "liblog_rust",
         "libnix",
         "libopenssl",
-        "libprotobuf",
+        "libprotobuf_deprecated",
         "librpcbinder_rs",
         "libthiserror",
     ],
diff --git a/compos/Android.bp b/compos/Android.bp
index 2f6be98..c120b0f 100644
--- a/compos/Android.bp
+++ b/compos/Android.bp
@@ -18,7 +18,7 @@
         "libminijail_rust",
         "libnix",
         "libodsign_proto_rust",
-        "libprotobuf",
+        "libprotobuf_deprecated",
         "libregex",
         "librpcbinder_rs",
         "librustutils",
diff --git a/compos/common/compos_client.rs b/compos/common/compos_client.rs
index 96c8147..bf4c678 100644
--- a/compos/common/compos_client.rs
+++ b/compos/common/compos_client.rs
@@ -19,7 +19,7 @@
 use crate::timeouts::TIMEOUTS;
 use crate::{
     get_vm_config_path, BUILD_MANIFEST_APK_PATH, BUILD_MANIFEST_SYSTEM_EXT_APK_PATH,
-    COMPOS_APEX_ROOT, COMPOS_DATA_ROOT, COMPOS_VSOCK_PORT,
+    COMPOS_APEX_ROOT, COMPOS_VSOCK_PORT,
 };
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
     CpuTopology::CpuTopology,
@@ -80,7 +80,6 @@
         let instance_fd = ParcelFileDescriptor::new(instance_image);
 
         let apex_dir = Path::new(COMPOS_APEX_ROOT);
-        let data_dir = Path::new(COMPOS_DATA_ROOT);
 
         let config_apk = locate_config_apk(apex_dir)?;
         let apk_fd = File::open(config_apk).context("Failed to open config APK file")?;
@@ -110,18 +109,6 @@
 
         let debug_level = if parameters.debug_mode { DebugLevel::FULL } else { DebugLevel::NONE };
 
-        let (console_fd, log_fd) = if debug_level == DebugLevel::NONE {
-            (None, None)
-        } else {
-            // Console output and the system log output from the VM are redirected to file.
-            let console_fd = File::create(data_dir.join("vm_console.log"))
-                .context("Failed to create console log file")?;
-            let log_fd = File::create(data_dir.join("vm.log"))
-                .context("Failed to create system log file")?;
-            info!("Running in debug level {:?}", debug_level);
-            (Some(console_fd), Some(log_fd))
-        };
-
         let cpu_topology = match parameters.cpu_topology {
             VmCpuTopology::OneCpu => CpuTopology::ONE_CPU,
             VmCpuTopology::MatchHost => CpuTopology::MATCH_HOST,
@@ -143,6 +130,8 @@
             gdbPort: 0, // Don't start gdb-server
         });
 
+        // Let logs go to logcat.
+        let (console_fd, log_fd) = (None, None);
         let callback = Box::new(Callback {});
         let instance = VmInstance::create(service, &config, console_fd, log_fd, Some(callback))
             .context("Failed to create VM")?;
diff --git a/compos/composd/Android.bp b/compos/composd/Android.bp
index b0294dd..f66de32 100644
--- a/compos/composd/Android.bp
+++ b/compos/composd/Android.bp
@@ -22,7 +22,7 @@
         "liblibc",
         "liblog_rust",
         "libodsign_proto_rust",
-        "libprotobuf",
+        "libprotobuf_deprecated",
         "librustutils",
         "libshared_child",
         "libvmclient",
diff --git a/compos/tests/java/android/compos/test/ComposTestCase.java b/compos/tests/java/android/compos/test/ComposTestCase.java
index 4e3d0a8..eb2e072 100644
--- a/compos/tests/java/android/compos/test/ComposTestCase.java
+++ b/compos/tests/java/android/compos/test/ComposTestCase.java
@@ -27,7 +27,6 @@
 
 import com.android.microdroid.test.host.CommandRunner;
 import com.android.microdroid.test.host.MicrodroidHostTestCaseBase;
-import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.result.FileInputStreamSource;
 import com.android.tradefed.result.LogDataType;
@@ -81,7 +80,7 @@
 
     @Before
     public void setUp() throws Exception {
-        testIfDeviceIsCapable(getDevice());
+        assumeDeviceIsCapable(getDevice());
 
         String value = getDevice().getProperty(SYSTEM_SERVER_COMPILER_FILTER_PROP_NAME);
         if (value == null) {
@@ -95,8 +94,6 @@
     public void tearDown() throws Exception {
         killVmAndReconnectAdb();
 
-        archiveVmLogsThenDelete("teardown");
-
         CommandRunner android = new CommandRunner(getDevice());
 
         // Clear up any CompOS instance files we created
@@ -113,19 +110,6 @@
         }
     }
 
-    private void archiveVmLogsThenDelete(String suffix) throws DeviceNotAvailableException {
-        archiveLogThenDelete(
-                mTestLogs,
-                getDevice(),
-                COMPOS_APEXDATA_DIR + "/vm_console.log",
-                "vm_console.log-" + suffix + "-" + mTestName.getMethodName());
-        archiveLogThenDelete(
-                mTestLogs,
-                getDevice(),
-                COMPOS_APEXDATA_DIR + "/vm.log",
-                "vm.log-" + suffix + "-" + mTestName.getMethodName());
-    }
-
     @Test
     public void testOdrefreshSpeed() throws Exception {
         getDevice().setProperty(SYSTEM_SERVER_COMPILER_FILTER_PROP_NAME, "speed");
@@ -170,10 +154,6 @@
         }
         killVmAndReconnectAdb();
 
-        // These logs are potentially useful, capture them before they are overwritten by
-        // compos_verify.
-        archiveVmLogsThenDelete("compile");
-
         // Expect the BCC extracted from the BCC to be well-formed.
         assertVmBccIsValid();
 
diff --git a/encryptedstore/src/main.rs b/encryptedstore/src/main.rs
index 7a41f13..86fa6da 100644
--- a/encryptedstore/src/main.rs
+++ b/encryptedstore/src/main.rs
@@ -125,9 +125,13 @@
 
 fn format_ext4(device: &Path) -> Result<()> {
     let mkfs_options = [
-        "-j",               // Create appropriate sized journal
-        "-O metadata_csum", // Metadata checksum for filesystem integrity
-        "-b 4096",          // block size in the filesystem
+        "-j", // Create appropriate sized journal
+        /* metadata_csum: enabled for filesystem integrity
+         * extents: Not enabling extents reduces the coverage of metadata checksumming.
+         * 64bit: larger fields afforded by this feature enable full-strength checksumming.
+         */
+        "-O metadata_csum, extents, 64bit",
+        "-b 4096", // block size in the filesystem
     ];
     let mut cmd = Command::new(MK2FS_BIN);
     let status = cmd
diff --git a/libs/devicemapper/src/lib.rs b/libs/devicemapper/src/lib.rs
index 4cf4e99..fec0114 100644
--- a/libs/devicemapper/src/lib.rs
+++ b/libs/devicemapper/src/lib.rs
@@ -227,8 +227,8 @@
     let context = Context::new(0);
     let now = SystemTime::now().duration_since(UNIX_EPOCH)?;
     let ts = Timestamp::from_unix(context, now.as_secs(), now.subsec_nanos());
-    let uuid = Uuid::new_v1(ts, node_id)?;
-    Ok(String::from(uuid.to_hyphenated().encode_lower(&mut Uuid::encode_buffer())))
+    let uuid = Uuid::new_v1(ts, node_id.try_into()?);
+    Ok(String::from(uuid.hyphenated().encode_lower(&mut Uuid::encode_buffer())))
 }
 
 #[cfg(test)]
diff --git a/microdroid/README.md b/microdroid/README.md
index f70965a..71be7d0 100644
--- a/microdroid/README.md
+++ b/microdroid/README.md
@@ -181,7 +181,8 @@
 
 microdroid can be started with debugging features by debug policies from the
 host. Host bootloader may provide debug policies to host OS's device tree for
-VMs.
+VMs. Host bootloader MUST NOT provide debug policies for locked devices for
+security reasons.
 
 For protected VM, such device tree will be available in microdroid. microdroid
 can check which debuging features is enabled.
diff --git a/microdroid/payload/metadata/Android.bp b/microdroid/payload/metadata/Android.bp
index cd182fc..e3138e8 100644
--- a/microdroid/payload/metadata/Android.bp
+++ b/microdroid/payload/metadata/Android.bp
@@ -12,7 +12,7 @@
     rustlibs: [
         "libanyhow",
         "libmicrodroid_metadata_proto_rust",
-        "libprotobuf",
+        "libprotobuf_deprecated",
     ],
     apex_available: [
         "com.android.virt",
diff --git a/pvmfw/README.md b/pvmfw/README.md
index 04ad8c4..2d2b253 100644
--- a/pvmfw/README.md
+++ b/pvmfw/README.md
@@ -197,16 +197,21 @@
 that it differs from the `BccHandover` defined by the specification in that its
 `Bcc` field is mandatory (while optional in the original).
 
-The handover expected by pvmfw can be generated as follows:
+Devices that fully implement DICE should provide a certificate rooted at the
+Unique Device Secret (UDS) in a boot stage preceding the pvmfw loader (typically
+ABL), in such a way that it would receive a valid `BccHandover`, that can be
+passed to [`BccHandoverMainFlow`][BccHandoverMainFlow] along with the inputs
+described below.
 
-- by passing a `BccHandover` received from a previous boot stage (_e.g._ Trusted
-  Firmware, ROM bootloader, ...) to
-  [`BccHandoverMainFlow`][BccHandoverMainFlow];
+Otherwise, as an intermediate step towards supporting DICE throughout the
+software stack of the device, incomplete implementations may root the BCC at the
+pvmfw loader, using an arbitrary constant as initial CDI. The pvmfw loader can
+easily do so by:
 
-- by generating a `BccHandover` (as an example, see [Trusty][Trusty-BCC]) with
-  both CDIs set to an arbitrary constant value and no `Bcc`, and pass it to
-  `BccHandoverMainFlow`, which will both derive the pvmfw CDIs and start a
-  valid certificate chain, making the pvmfw loader the root of the BCC.
+1. Building a BCC-less `BccHandover` using CBOR operations
+   ([example][Trusty-BCC]) and containing the constant CDIs
+1. Passing the resulting `BccHandover` to `BccHandoverMainFlow` as described
+   above
 
 The recommended DICE inputs at this stage are:
 
@@ -240,7 +245,10 @@
 Config header can provide a DTBO to be overlaid on top of the baseline device
 tree from crosvm.
 
-The DTBO may contain debug policies as follows.
+The DTBO may contain debug policies. Debug policies MUST NOT be provided for
+locked devices for security reasons.
+
+Here are an example of DTBO.
 
 ```
 / {
diff --git a/pvmfw/src/exceptions.rs b/pvmfw/src/exceptions.rs
index 03fc220..42f4c3b 100644
--- a/pvmfw/src/exceptions.rs
+++ b/pvmfw/src/exceptions.rs
@@ -14,22 +14,21 @@
 
 //! Exception handlers.
 
-use crate::helpers::page_4kb_of;
-use core::arch::asm;
+use crate::{helpers::page_4kb_of, read_sysreg};
 use vmbase::console;
 use vmbase::{console::emergency_write_str, eprintln, power::reboot};
 
-const ESR_32BIT_EXT_DABT: u64 = 0x96000010;
+const ESR_32BIT_EXT_DABT: usize = 0x96000010;
 const UART_PAGE: usize = page_4kb_of(console::BASE_ADDRESS);
 
 #[no_mangle]
 extern "C" fn sync_exception_current(_elr: u64, _spsr: u64) {
-    let esr = read_esr();
-    let far = read_far();
+    let esr = read_sysreg!("esr_el1");
+    let far = read_sysreg!("far_el1");
     // Don't print to the UART if we're handling the exception it could raise.
-    if esr != ESR_32BIT_EXT_DABT || page_4kb_of(far as usize) != UART_PAGE {
+    if esr != ESR_32BIT_EXT_DABT || page_4kb_of(far) != UART_PAGE {
         emergency_write_str("sync_exception_current\n");
-        print_esr(esr);
+        eprintln!("esr={esr:#08x}");
     }
     reboot();
 }
@@ -48,17 +47,17 @@
 
 #[no_mangle]
 extern "C" fn serr_current(_elr: u64, _spsr: u64) {
-    let esr = read_esr();
+    let esr = read_sysreg!("esr_el1");
     emergency_write_str("serr_current\n");
-    print_esr(esr);
+    eprintln!("esr={esr:#08x}");
     reboot();
 }
 
 #[no_mangle]
 extern "C" fn sync_lower(_elr: u64, _spsr: u64) {
-    let esr = read_esr();
+    let esr = read_sysreg!("esr_el1");
     emergency_write_str("sync_lower\n");
-    print_esr(esr);
+    eprintln!("esr={esr:#08x}");
     reboot();
 }
 
@@ -76,31 +75,8 @@
 
 #[no_mangle]
 extern "C" fn serr_lower(_elr: u64, _spsr: u64) {
-    let esr = read_esr();
+    let esr = read_sysreg!("esr_el1");
     emergency_write_str("serr_lower\n");
-    print_esr(esr);
+    eprintln!("esr={esr:#08x}");
     reboot();
 }
-
-#[inline]
-fn read_esr() -> u64 {
-    let mut esr: u64;
-    unsafe {
-        asm!("mrs {esr}, esr_el1", esr = out(reg) esr);
-    }
-    esr
-}
-
-#[inline]
-fn print_esr(esr: u64) {
-    eprintln!("esr={:#08x}", esr);
-}
-
-#[inline]
-fn read_far() -> u64 {
-    let mut far: u64;
-    unsafe {
-        asm!("mrs {far}, far_el1", far = out(reg) far);
-    }
-    far
-}
diff --git a/pvmfw/src/helpers.rs b/pvmfw/src/helpers.rs
index 4df9386..6310826 100644
--- a/pvmfw/src/helpers.rs
+++ b/pvmfw/src/helpers.rs
@@ -22,6 +22,39 @@
 
 pub const GUEST_PAGE_SIZE: usize = SIZE_4KB;
 
+/// Read a value from a system register.
+#[macro_export]
+macro_rules! read_sysreg {
+    ($sysreg:literal) => {{
+        let mut r: usize;
+        // Safe because it reads a system register and does not affect Rust.
+        unsafe {
+            core::arch::asm!(
+                concat!("mrs {}, ", $sysreg),
+                out(reg) r,
+                options(nomem, nostack, preserves_flags),
+            )
+        }
+        r
+    }};
+}
+
+/// Write a value to a system register.
+#[macro_export]
+macro_rules! write_sysreg {
+    ($sysreg:literal, $val:expr) => {{
+        let value: usize = $val;
+        // Safe because it writes a system register and does not affect Rust.
+        unsafe {
+            core::arch::asm!(
+                concat!("msr ", $sysreg, ", {}"),
+                in(reg) value,
+                options(nomem, nostack, preserves_flags),
+            )
+        }
+    }};
+}
+
 /// Computes the largest multiple of the provided alignment smaller or equal to the address.
 ///
 /// Note: the result is undefined if alignment isn't a power of two.
@@ -78,9 +111,7 @@
 fn min_dcache_line_size() -> usize {
     const DMINLINE_SHIFT: usize = 16;
     const DMINLINE_MASK: usize = 0xf;
-    let ctr_el0: usize;
-
-    unsafe { asm!("mrs {x}, ctr_el0", x = out(reg) ctr_el0) }
+    let ctr_el0 = read_sysreg!("ctr_el0");
 
     // DminLine: log2 of the number of words in the smallest cache line of all the data caches.
     let dminline = (ctr_el0 >> DMINLINE_SHIFT) & DMINLINE_MASK;
@@ -97,7 +128,13 @@
 
     for line in (start..end).step_by(line_size) {
         // SAFETY - Clearing cache lines shouldn't have Rust-visible side effects.
-        unsafe { asm!("dc cvau, {x}", x = in(reg) line) }
+        unsafe {
+            asm!(
+                "dc cvau, {x}",
+                x = in(reg) line,
+                options(nomem, nostack, preserves_flags),
+            )
+        }
     }
 }
 
diff --git a/pvmfw/src/instance.rs b/pvmfw/src/instance.rs
index fbf2040..a974543 100644
--- a/pvmfw/src/instance.rs
+++ b/pvmfw/src/instance.rs
@@ -258,11 +258,11 @@
 
 impl EntryHeader {
     fn new(uuid: Uuid, payload_size: usize) -> Self {
-        Self { uuid: uuid.as_u128(), payload_size: u64::try_from(payload_size).unwrap().to_le() }
+        Self { uuid: uuid.to_u128_le(), payload_size: u64::try_from(payload_size).unwrap().to_le() }
     }
 
     fn uuid(&self) -> Uuid {
-        Uuid::from_u128(self.uuid)
+        Uuid::from_u128_le(self.uuid)
     }
 
     fn payload_size(&self) -> usize {
diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs
index 577ad6e..00ff61f 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -16,7 +16,6 @@
 
 #![no_main]
 #![no_std]
-#![feature(default_alloc_error_handler)]
 
 extern crate alloc;
 
diff --git a/rialto/src/main.rs b/rialto/src/main.rs
index 3b730f4..59ee0b6 100644
--- a/rialto/src/main.rs
+++ b/rialto/src/main.rs
@@ -16,7 +16,6 @@
 
 #![no_main]
 #![no_std]
-#![feature(default_alloc_error_handler)]
 
 mod exceptions;
 
diff --git a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
index 9851a17..c210ea6 100644
--- a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
+++ b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
@@ -45,6 +45,7 @@
 import com.android.microdroid.testservice.IBenchmarkService;
 import com.android.microdroid.testservice.ITestService;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -54,6 +55,7 @@
 
 import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -97,6 +99,19 @@
 
     private Instrumentation mInstrumentation;
 
+    private boolean mTeardownDebugfs;
+
+    private void setupDebugfs() throws IOException {
+        BufferedReader reader = new BufferedReader(new FileReader("/proc/mounts"));
+
+        mTeardownDebugfs =
+                !reader.lines().filter(line -> line.startsWith("debugfs ")).findAny().isPresent();
+
+        if (mTeardownDebugfs) {
+            executeCommand("mount -t debugfs none /sys/kernel/debug");
+        }
+    }
+
     @Before
     public void setup() throws IOException {
         grantPermission(VirtualMachine.MANAGE_VIRTUAL_MACHINE_PERMISSION);
@@ -106,6 +121,13 @@
         mInstrumentation = getInstrumentation();
     }
 
+    @After
+    public void tearDown() throws IOException {
+        if (mTeardownDebugfs) {
+            executeCommand("umount /sys/kernel/debug");
+        }
+    }
+
     private boolean canBootMicrodroidWithMemory(int mem)
             throws VirtualMachineException, InterruptedException, IOException {
         VirtualMachineConfig normalConfig =
@@ -346,17 +368,15 @@
         public final long mGuestRss;
         public final long mGuestPss;
 
-        CrosvmStats(Function<String, String> shellExecutor) {
+        CrosvmStats(int vmPid, Function<String, String> shellExecutor) {
             try {
-                int crosvmPid = ProcessUtil.getCrosvmPid(Os.getpid(), shellExecutor);
-
                 long hostRss = 0;
                 long hostPss = 0;
                 long guestRss = 0;
                 long guestPss = 0;
                 boolean hasGuestMaps = false;
                 for (ProcessUtil.SMapEntry entry :
-                        ProcessUtil.getProcessSmaps(crosvmPid, shellExecutor)) {
+                        ProcessUtil.getProcessSmaps(vmPid, shellExecutor)) {
                     long rss = entry.metrics.get("Rss");
                     long pss = entry.metrics.get("Pss");
                     if (entry.name.contains("crosvm_guest")) {
@@ -383,6 +403,54 @@
         }
     }
 
+    private static class KvmVmStats {
+        public final long mProtectedHyp;
+        public final long mProtectedShared;
+        private final Function<String, String> mShellExecutor;
+        private static final String KVM_STATS_FS = "/sys/kernel/debug/kvm";
+
+        public static KvmVmStats createIfSupported(
+                int vmPid, Function<String, String> shellExecutor) {
+
+            if (!new File(KVM_STATS_FS + "/protected_hyp_mem").exists()) {
+                return null;
+            }
+
+            return new KvmVmStats(vmPid, shellExecutor);
+        }
+
+        KvmVmStats(int vmPid, Function<String, String> shellExecutor) {
+            mShellExecutor = shellExecutor;
+
+            try {
+                String dir = getKvmVmStatDir(vmPid);
+
+                mProtectedHyp = getKvmVmStat(dir, "protected_hyp_mem");
+                mProtectedShared = getKvmVmStat(dir, "protected_shared_mem");
+
+            } catch (Exception e) {
+                Log.e(TAG, "Error inside onPayloadReady():" + e);
+                throw new RuntimeException(e);
+            }
+        }
+
+        private String getKvmVmStatDir(int vmPid) {
+            String output = mShellExecutor.apply("find " + KVM_STATS_FS + " -type d");
+
+            for (String line : output.split("\n")) {
+                if (line.startsWith(KVM_STATS_FS + "/" + Integer.toString(vmPid) + "-")) {
+                    return line;
+                }
+            }
+
+            throw new IllegalStateException("KVM stat folder for PID " + vmPid + " not found");
+        }
+
+        private int getKvmVmStat(String dir, String name) throws IOException {
+            return Integer.parseInt(mShellExecutor.apply("cat " + dir + "/" + name).trim());
+        }
+    }
+
     @Test
     public void testMemoryUsage() throws Exception {
         final String vmName = "test_vm_mem_usage";
@@ -394,6 +462,9 @@
                         .build();
         VirtualMachine vm = forceCreateNewVirtualMachine(vmName, config);
         MemoryUsageListener listener = new MemoryUsageListener(this::executeCommand);
+
+        setupDebugfs();
+
         BenchmarkVmListener.create(listener).runToFinish(TAG, vm);
 
         double mem_overall = 256.0;
@@ -423,6 +494,12 @@
         bundle.putDouble(METRIC_NAME_PREFIX + "mem_crosvm_host_pss_MB", mem_crosvm_host_pss);
         bundle.putDouble(METRIC_NAME_PREFIX + "mem_crosvm_guest_rss_MB", mem_crosvm_guest_rss);
         bundle.putDouble(METRIC_NAME_PREFIX + "mem_crosvm_guest_pss_MB", mem_crosvm_guest_pss);
+        if (listener.mKvm != null) {
+            double mem_protected_shared = (double) listener.mKvm.mProtectedShared / 1048576.0;
+            double mem_protected_hyp = (double) listener.mKvm.mProtectedHyp / 1048576.0;
+            bundle.putDouble(METRIC_NAME_PREFIX + "mem_protected_shared_MB", mem_protected_shared);
+            bundle.putDouble(METRIC_NAME_PREFIX + "mem_protected_hyp_MB", mem_protected_hyp);
+        }
         mInstrumentation.sendStatus(0, bundle);
     }
 
@@ -441,17 +518,21 @@
         public long mSlab;
 
         public CrosvmStats mCrosvm;
+        public KvmVmStats mKvm;
 
         @Override
         public void onPayloadReady(VirtualMachine vm, IBenchmarkService service)
                 throws RemoteException {
+            int vmPid = ProcessUtil.getCrosvmPid(Os.getpid(), mShellExecutor);
+
             mMemTotal = service.getMemInfoEntry("MemTotal");
             mMemFree = service.getMemInfoEntry("MemFree");
             mMemAvailable = service.getMemInfoEntry("MemAvailable");
             mBuffers = service.getMemInfoEntry("Buffers");
             mCached = service.getMemInfoEntry("Cached");
             mSlab = service.getMemInfoEntry("Slab");
-            mCrosvm = new CrosvmStats(mShellExecutor);
+            mCrosvm = new CrosvmStats(vmPid, mShellExecutor);
+            mKvm = KvmVmStats.createIfSupported(vmPid, mShellExecutor);
         }
     }
 
@@ -511,10 +592,12 @@
         @SuppressWarnings("ReturnValueIgnored")
         public void onPayloadReady(VirtualMachine vm, IBenchmarkService service)
                 throws RemoteException {
+            int vmPid = ProcessUtil.getCrosvmPid(Os.getpid(), mShellExecutor);
+
             // Allocate 256MB of anonymous memory. This will fill all guest
             // memory and cause swapping to start.
             service.allocAnonMemory(256);
-            mPreCrosvm = new CrosvmStats(mShellExecutor);
+            mPreCrosvm = new CrosvmStats(vmPid, mShellExecutor);
             // Send a memory trim hint to cause memory reclaim.
             mShellExecutor.apply("am send-trim-memory " + Process.myPid() + " RUNNING_CRITICAL");
             // Give time for the memory reclaim to do its work.
@@ -524,7 +607,7 @@
                 Log.e(TAG, "Interrupted sleep:" + e);
                 Thread.currentThread().interrupt();
             }
-            mPostCrosvm = new CrosvmStats(mShellExecutor);
+            mPostCrosvm = new CrosvmStats(vmPid, mShellExecutor);
         }
     }
 
diff --git a/tests/benchmark_hostside/java/android/avf/test/AVFHostTestCase.java b/tests/benchmark_hostside/java/android/avf/test/AVFHostTestCase.java
index 9c8714f..8c6218c 100644
--- a/tests/benchmark_hostside/java/android/avf/test/AVFHostTestCase.java
+++ b/tests/benchmark_hostside/java/android/avf/test/AVFHostTestCase.java
@@ -85,9 +85,14 @@
 
     private boolean mNeedTearDown = false;
 
+    private boolean mNeedToRestartPkvmStatus = false;
+
     @Before
     public void setUp() throws Exception {
-        testIfDeviceIsCapable(getDevice());
+        mNeedTearDown = false;
+        mNeedToRestartPkvmStatus = false;
+
+        assumeDeviceIsCapable(getDevice());
         mNeedTearDown = true;
 
         getDevice().installPackage(findTestFile(APK_NAME), /* reinstall */ false);
@@ -99,12 +104,12 @@
     public void tearDown() throws Exception {
         if (!mNeedTearDown) {
             // If we skipped setUp, we don't need to undo it, and that avoids potential exceptions
-            // incompatible hardware. (Note that tests can change what testIfDeviceIsCapable()
+            // incompatible hardware. (Note that tests can change what assumeDeviceIsCapable()
             // sees, so we can't rely on that - b/268688303.)
             return;
         }
-        // Set PKVM enable and reboot to prevent previous staged session.
-        if (!isCuttlefish()) {
+        // Restore PKVM status and reboot to prevent previous staged session, if switched.
+        if (mNeedToRestartPkvmStatus) {
             setPKVMStatusWithRebootToBootloader(true);
             rebootFromBootloaderAndWaitBootCompleted();
         }
@@ -422,7 +427,7 @@
     }
 
     private void enableDisablePKVMTestHelper(boolean isEnable) throws Exception {
-        skipIfPKVMStatusSwitchNotSupported();
+        assumePKVMStatusSwitchSupported();
 
         List<Double> bootDmesgTime = new ArrayList<>(ROUND_COUNT);
         Map<String, List<Double>> bootloaderTime = new HashMap<>();
@@ -478,9 +483,15 @@
         reportMetric(bootDmesgTime, "dmesg_boot_time_" + suffix, "s");
     }
 
-    private void skipIfPKVMStatusSwitchNotSupported() throws Exception {
+    private void assumePKVMStatusSwitchSupported() throws Exception {
         assumeFalse("Skip on CF; can't reboot to bootloader", isCuttlefish());
 
+        // This is an overkill. The intention is to exclude remote_device_proxy, which uses
+        // different serial for fastboot. But there's no good way to distinguish from regular IP
+        // transport. This is currently not a problem until someone really needs to run the test
+        // over regular IP transport.
+        assumeFalse("Skip over IP (overkill for remote_device_proxy)", getDevice().isAdbTcp());
+
         if (!getDevice().isStateBootloaderOrFastbootd()) {
             getDevice().rebootIntoBootloader();
         }
@@ -513,6 +524,7 @@
     }
 
     private void setPKVMStatusWithRebootToBootloader(boolean isEnable) throws Exception {
+        mNeedToRestartPkvmStatus = true;
 
         if (!getDevice().isStateBootloaderOrFastbootd()) {
             getDevice().rebootIntoBootloader();
diff --git a/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java b/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java
index a7f7906..4807c0f 100644
--- a/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java
+++ b/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java
@@ -97,7 +97,7 @@
                 DeviceProperties.create(getDevice()::getProperty).getMetricsTag());
     }
 
-    public static void testIfDeviceIsCapable(ITestDevice androidDevice) throws Exception {
+    public static void assumeDeviceIsCapable(ITestDevice androidDevice) throws Exception {
         assumeTrue("Need an actual TestDevice", androidDevice instanceof TestDevice);
         TestDevice testDevice = (TestDevice) androidDevice;
         assumeTrue(
diff --git a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
index 687756e..dabb31d 100644
--- a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
+++ b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
@@ -24,7 +24,6 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
@@ -82,6 +81,7 @@
 import java.util.function.Function;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class MicrodroidHostTests extends MicrodroidHostTestCaseBase {
@@ -682,19 +682,24 @@
         microdroid.waitForBootComplete(BOOT_COMPLETE_TIMEOUT);
         device.shutdownMicrodroid(microdroid);
 
+        // Try to collect atoms for 60000 milliseconds.
         List<StatsLog.EventMetricData> data = new ArrayList<>();
-        assertThatEventually(
-                10000,
-                () -> {
-                    data.addAll(ReportUtils.getEventMetricDataList(getDevice()));
-                    return data.size();
-                },
-                is(3)
-        );
+        long start = System.currentTimeMillis();
+        while ((System.currentTimeMillis() - start < 60000) && data.size() < 3) {
+            data.addAll(ReportUtils.getEventMetricDataList(getDevice()));
+            Thread.sleep(500);
+        }
+        assertThat(
+                        data.stream()
+                                .map(x -> x.getAtom().getPushedCase().getNumber())
+                                .collect(Collectors.toList()))
+                .containsExactly(
+                        AtomsProto.Atom.VM_CREATION_REQUESTED_FIELD_NUMBER,
+                        AtomsProto.Atom.VM_BOOTED_FIELD_NUMBER,
+                        AtomsProto.Atom.VM_EXITED_FIELD_NUMBER)
+                .inOrder();
 
         // Check VmCreationRequested atom
-        assertThat(data.get(0).getAtom().getPushedCase().getNumber()).isEqualTo(
-                AtomsProto.Atom.VM_CREATION_REQUESTED_FIELD_NUMBER);
         AtomsProto.VmCreationRequested atomVmCreationRequested =
                 data.get(0).getAtom().getVmCreationRequested();
         assertThat(atomVmCreationRequested.getHypervisor())
@@ -711,14 +716,10 @@
                 .isEqualTo("com.android.art:com.android.compos:com.android.sdkext");
 
         // Check VmBooted atom
-        assertThat(data.get(1).getAtom().getPushedCase().getNumber())
-                .isEqualTo(AtomsProto.Atom.VM_BOOTED_FIELD_NUMBER);
         AtomsProto.VmBooted atomVmBooted = data.get(1).getAtom().getVmBooted();
         assertThat(atomVmBooted.getVmIdentifier()).isEqualTo("VmRunApp");
 
         // Check VmExited atom
-        assertThat(data.get(2).getAtom().getPushedCase().getNumber())
-                .isEqualTo(AtomsProto.Atom.VM_EXITED_FIELD_NUMBER);
         AtomsProto.VmExited atomVmExited = data.get(2).getAtom().getVmExited();
         assertThat(atomVmExited.getVmIdentifier()).isEqualTo("VmRunApp");
         assertThat(atomVmExited.getDeathReason()).isEqualTo(AtomsProto.VmExited.DeathReason.KILLED);
@@ -927,6 +928,21 @@
         checkHashAlgorithm(virtApexEtcDir);
     }
 
+    @Test
+    @CddTest
+    public void testNoAvfDebugPolicyInLockedDevice() throws Exception {
+        ITestDevice device = getDevice();
+
+        // Check device's locked state with ro.boot.verifiedbootstate. ro.boot.flash.locked
+        // may not be set if ro.oem_unlock_supported is false.
+        String lockProp = device.getProperty("ro.boot.verifiedbootstate");
+        assumeFalse("Unlocked devices may have AVF debug policy", lockProp.equals("orange"));
+
+        // Test that AVF debug policy doesn't exist.
+        boolean hasDebugPolicy = device.doesFileExist("/sys/firmware/devicetree/base/avf");
+        assertThat(hasDebugPolicy).isFalse();
+    }
+
     private String avbInfo(String image_path) throws Exception {
         File avbtool = findTestFile("avbtool");
         List<String> command =
@@ -970,7 +986,7 @@
 
     @Before
     public void setUp() throws Exception {
-        testIfDeviceIsCapable(getDevice());
+        assumeDeviceIsCapable(getDevice());
         mMetricPrefix = getMetricPrefix() + "microdroid/";
         mMicrodroidDevice = null;
 
diff --git a/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java b/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java
index ddcc866..0f6d095 100644
--- a/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java
+++ b/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java
@@ -97,6 +97,9 @@
     @Before
     public void setUp() throws Exception {
         mAndroidDevice = (TestDevice) Objects.requireNonNull(getDevice());
+
+        // Check device capabilities
+        assumeDeviceIsCapable(mAndroidDevice);
         assumeTrue(
                 "Skip if protected VMs are not supported",
                 mAndroidDevice.supportsMicrodroid(/* protectedVm= */ true));
@@ -111,12 +114,6 @@
         mBccFileOnHost =
                 getTestInformation().getDependencyFile(BCC_FILE_NAME, /* targetFirst= */ false);
 
-        // Check device capability
-        testIfDeviceIsCapable(mAndroidDevice);
-        assumeTrue(
-                "Protected VMs are not supported",
-                mAndroidDevice.supportsMicrodroid(/*protectedVm=*/ true));
-
         // Prepare for loading pvmfw.bin
         // File will be setup in individual test,
         // and then pushed to device in launchProtectedVmAndWaitForBootCompleted.
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 b7dbcd8..7044ae7 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -66,7 +66,6 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.function.ThrowingRunnable;
@@ -1183,7 +1182,6 @@
     }
 
     @Test
-    @Ignore("b/249723852")
     @CddTest(requirements = {
             "9.17/C-1-1",
             "9.17/C-2-7"
diff --git a/vmbase/example/src/main.rs b/vmbase/example/src/main.rs
index 3b0e9db..9ec2dc4 100644
--- a/vmbase/example/src/main.rs
+++ b/vmbase/example/src/main.rs
@@ -16,7 +16,6 @@
 
 #![no_main]
 #![no_std]
-#![feature(default_alloc_error_handler)]
 
 mod exceptions;
 mod layout;
diff --git a/vmbase/example/src/pci.rs b/vmbase/example/src/pci.rs
index c0a2d2b..117cbc8 100644
--- a/vmbase/example/src/pci.rs
+++ b/vmbase/example/src/pci.rs
@@ -20,7 +20,7 @@
 use fdtpci::PciInfo;
 use log::{debug, info};
 use virtio_drivers::{
-    device::blk::VirtIOBlk,
+    device::{blk::VirtIOBlk, console::VirtIOConsole},
     transport::{
         pci::{bus::PciRoot, virtio_device_type, PciTransport},
         DeviceType, Transport,
@@ -53,29 +53,41 @@
         }
     }
 
-    assert_eq!(checked_virtio_device_count, 1);
+    assert_eq!(checked_virtio_device_count, 4);
 }
 
 /// Checks the given VirtIO device, if we know how to.
 ///
 /// Returns true if the device was checked, or false if it was ignored.
 fn check_virtio_device(transport: impl Transport, device_type: DeviceType) -> bool {
-    if device_type == DeviceType::Block {
-        let mut blk = VirtIOBlk::<HalImpl, _>::new(transport).expect("failed to create blk driver");
-        info!("Found {} KiB block device.", blk.capacity() * SECTOR_SIZE_BYTES as u64 / 1024);
-        assert_eq!(blk.capacity(), EXPECTED_SECTOR_COUNT as u64);
-        let mut data = [0; SECTOR_SIZE_BYTES * EXPECTED_SECTOR_COUNT];
-        for i in 0..EXPECTED_SECTOR_COUNT {
-            blk.read_block(i, &mut data[i * SECTOR_SIZE_BYTES..(i + 1) * SECTOR_SIZE_BYTES])
-                .expect("Failed to read block device.");
+    match device_type {
+        DeviceType::Block => {
+            let mut blk =
+                VirtIOBlk::<HalImpl, _>::new(transport).expect("failed to create blk driver");
+            info!("Found {} KiB block device.", blk.capacity() * SECTOR_SIZE_BYTES as u64 / 1024);
+            assert_eq!(blk.capacity(), EXPECTED_SECTOR_COUNT as u64);
+            let mut data = [0; SECTOR_SIZE_BYTES * EXPECTED_SECTOR_COUNT];
+            for i in 0..EXPECTED_SECTOR_COUNT {
+                blk.read_block(i, &mut data[i * SECTOR_SIZE_BYTES..(i + 1) * SECTOR_SIZE_BYTES])
+                    .expect("Failed to read block device.");
+            }
+            for (i, chunk) in data.chunks(size_of::<u32>()).enumerate() {
+                assert_eq!(chunk, &(i as u32).to_le_bytes());
+            }
+            info!("Read expected data from block device.");
+            true
         }
-        for (i, chunk) in data.chunks(size_of::<u32>()).enumerate() {
-            assert_eq!(chunk, &(i as u32).to_le_bytes());
+        DeviceType::Console => {
+            let mut console = VirtIOConsole::<HalImpl, _>::new(transport)
+                .expect("Failed to create VirtIO console driver");
+            info!("Found console device: {:?}", console.info());
+            for &c in b"Hello VirtIO console\n" {
+                console.send(c).expect("Failed to send character to VirtIO console device");
+            }
+            info!("Wrote to VirtIO console.");
+            true
         }
-        info!("Read expected data from block device.");
-        true
-    } else {
-        false
+        _ => false,
     }
 }
 
diff --git a/vmbase/example/tests/test.rs b/vmbase/example/tests/test.rs
index 930e137..8f0eaa5 100644
--- a/vmbase/example/tests/test.rs
+++ b/vmbase/example/tests/test.rs
@@ -25,7 +25,7 @@
 use log::info;
 use std::{
     fs::File,
-    io::{self, BufRead, BufReader, Write},
+    io::{self, BufRead, BufReader, Read, Write},
     os::unix::io::FromRawFd,
     panic, thread,
 };
@@ -90,8 +90,8 @@
         gdbPort: 0, // no gdb
     });
     let console = android_log_fd()?;
-    let log = android_log_fd()?;
-    let vm = VmInstance::create(service.as_ref(), &config, Some(console), Some(log), None)
+    let (mut log_reader, log_writer) = pipe()?;
+    let vm = VmInstance::create(service.as_ref(), &config, Some(console), Some(log_writer), None)
         .context("Failed to create VM")?;
     vm.start().context("Failed to start VM")?;
     info!("Started example VM.");
@@ -100,15 +100,17 @@
     let death_reason = vm.wait_for_death();
     assert_eq!(death_reason, DeathReason::Shutdown);
 
+    // Check that the expected string was written to the log VirtIO console device.
+    let expected = "Hello VirtIO console\n";
+    let mut log_output = String::new();
+    assert_eq!(log_reader.read_to_string(&mut log_output)?, expected.len());
+    assert_eq!(log_output, expected);
+
     Ok(())
 }
 
 fn android_log_fd() -> io::Result<File> {
-    let (reader_fd, writer_fd) = nix::unistd::pipe()?;
-
-    // SAFETY: These are new FDs with no previous owner.
-    let reader = unsafe { File::from_raw_fd(reader_fd) };
-    let writer = unsafe { File::from_raw_fd(writer_fd) };
+    let (reader, writer) = pipe()?;
 
     thread::spawn(|| {
         for line in BufReader::new(reader).lines() {
@@ -117,3 +119,13 @@
     });
     Ok(writer)
 }
+
+fn pipe() -> io::Result<(File, File)> {
+    let (reader_fd, writer_fd) = nix::unistd::pipe()?;
+
+    // SAFETY: These are new FDs with no previous owner.
+    let reader = unsafe { File::from_raw_fd(reader_fd) };
+    let writer = unsafe { File::from_raw_fd(writer_fd) };
+
+    Ok((reader, writer))
+}