Merge changes I2145a7ed,Iacd188cb,Ib672b23b

* changes:
  Update template DT
  Patch DT using information extracted from DT
  Refactor DT validation routine
diff --git a/apex/product_packages.mk b/apex/product_packages.mk
index 4293c80..ef84551 100644
--- a/apex/product_packages.mk
+++ b/apex/product_packages.mk
@@ -19,6 +19,9 @@
 # To include the APEX in your build, insert this in your device.mk:
 #   $(call inherit-product, packages/modules/Virtualization/apex/product_packages.mk)
 
+# If devices supports AVF it implies that it uses non-flattened APEXes.
+$(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)
+
 PRODUCT_PACKAGES += \
     com.android.compos \
 
diff --git a/authfs/fd_server/Android.bp b/authfs/fd_server/Android.bp
index 5097408..db1fd44 100644
--- a/authfs/fd_server/Android.bp
+++ b/authfs/fd_server/Android.bp
@@ -12,6 +12,7 @@
         "libauthfs_fsverity_metadata",
         "libbinder_rs",
         "libclap",
+        "libfsverity_rs",
         "liblibc",
         "liblog_rust",
         "libnix",
@@ -31,6 +32,7 @@
         "libauthfs_fsverity_metadata",
         "libbinder_rs",
         "libclap",
+        "libfsverity_rs",
         "liblibc",
         "liblog_rust",
         "libnix",
diff --git a/authfs/fd_server/src/aidl.rs b/authfs/fd_server/src/aidl.rs
index 01b8209..ada3ffb 100644
--- a/authfs/fd_server/src/aidl.rs
+++ b/authfs/fd_server/src/aidl.rs
@@ -31,7 +31,6 @@
 use std::path::{Component, Path, PathBuf, MAIN_SEPARATOR};
 use std::sync::{Arc, RwLock};
 
-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/fsverity.rs b/authfs/fd_server/src/fsverity.rs
deleted file mode 100644
index 576f9dd..0000000
--- a/authfs/fd_server/src/fsverity.rs
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.
- */
-
-use nix::ioctl_readwrite;
-use std::io;
-
-// Constants/values from uapi/linux/fsverity.h
-const FS_VERITY_METADATA_TYPE_MERKLE_TREE: u64 = 1;
-const FS_VERITY_METADATA_TYPE_SIGNATURE: u64 = 3;
-const FS_IOCTL_MAGIC: u8 = b'f';
-const FS_IOCTL_READ_VERITY_METADATA: u8 = 135;
-
-#[repr(C)]
-pub struct fsverity_read_metadata_arg {
-    metadata_type: u64,
-    offset: u64,
-    length: u64,
-    buf_ptr: u64,
-    __reserved: u64,
-}
-
-ioctl_readwrite!(
-    read_verity_metadata,
-    FS_IOCTL_MAGIC,
-    FS_IOCTL_READ_VERITY_METADATA,
-    fsverity_read_metadata_arg
-);
-
-fn read_metadata(fd: i32, metadata_type: u64, offset: u64, buf: &mut [u8]) -> io::Result<usize> {
-    let mut arg = fsverity_read_metadata_arg {
-        metadata_type,
-        offset,
-        length: buf.len() as u64,
-        buf_ptr: buf.as_mut_ptr() as u64,
-        __reserved: 0,
-    };
-    Ok(unsafe { read_verity_metadata(fd, &mut arg) }? as usize)
-}
-
-/// Read the raw Merkle tree from the fd, if it exists. The API semantics is similar to a regular
-/// pread(2), and may not return full requested buffer.
-pub fn read_merkle_tree(fd: i32, offset: u64, buf: &mut [u8]) -> io::Result<usize> {
-    read_metadata(fd, FS_VERITY_METADATA_TYPE_MERKLE_TREE, offset, buf)
-}
-
-/// Read the fs-verity signature from the fd (if exists). The returned signature should be complete.
-pub fn read_signature(fd: i32, buf: &mut [u8]) -> io::Result<usize> {
-    read_metadata(fd, FS_VERITY_METADATA_TYPE_SIGNATURE, 0 /* offset */, buf)
-}
diff --git a/authfs/fd_server/src/main.rs b/authfs/fd_server/src/main.rs
index f91ebec..47983cb 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 fsverity;
 
 use anyhow::{bail, Result};
 use clap::Parser;
diff --git a/authfs/tests/common/src/java/com/android/fs/common/AuthFsTestRule.java b/authfs/tests/common/src/java/com/android/fs/common/AuthFsTestRule.java
index 357edea..7c85797 100644
--- a/authfs/tests/common/src/java/com/android/fs/common/AuthFsTestRule.java
+++ b/authfs/tests/common/src/java/com/android/fs/common/AuthFsTestRule.java
@@ -88,7 +88,7 @@
     private static CommandRunner sAndroid;
     private static CommandRunner sMicrodroid;
 
-    private final ExecutorService mThreadPool = Executors.newCachedThreadPool();
+    private ExecutorService mThreadPool;
 
     public static void setUpAndroid(TestInformation testInfo) throws Exception {
         assertNotNull(testInfo.getDevice());
@@ -242,6 +242,7 @@
     }
 
     public void setUpTest() throws Exception {
+        mThreadPool = Executors.newCachedThreadPool();
         if (sAndroid != null) {
             sAndroid.run("mkdir -p " + TEST_OUTPUT_DIR);
         }
@@ -264,5 +265,10 @@
         archiveLogThenDelete(this, getDevice(), vmRecentLog, "vm_recent.log-" + testName);
 
         sAndroid.run("rm -rf " + TEST_OUTPUT_DIR);
+
+        if (mThreadPool != null) {
+            mThreadPool.shutdownNow();
+            mThreadPool = null;
+        }
     }
 }
diff --git a/compos/composd/Android.bp b/compos/composd/Android.bp
index cee4b01..b0294dd 100644
--- a/compos/composd/Android.bp
+++ b/compos/composd/Android.bp
@@ -16,10 +16,13 @@
         "libbinder_rs",
         "libcompos_common",
         "libcomposd_native_rust",
+        "libfsverity_rs",
         "libminijail_rust",
         "libnix",
         "liblibc",
         "liblog_rust",
+        "libodsign_proto_rust",
+        "libprotobuf",
         "librustutils",
         "libshared_child",
         "libvmclient",
diff --git a/compos/composd/aidl/android/system/composd/ICompilationTaskCallback.aidl b/compos/composd/aidl/android/system/composd/ICompilationTaskCallback.aidl
index 569bba5..a3ce553 100644
--- a/compos/composd/aidl/android/system/composd/ICompilationTaskCallback.aidl
+++ b/compos/composd/aidl/android/system/composd/ICompilationTaskCallback.aidl
@@ -25,6 +25,8 @@
         CompilationFailed,
         /** We ran compilation in the VM, but it reported a problem. */
         UnexpectedCompilationResult,
+        /** We failed to enable fs-verity completely to the output artifacts. */
+        FailedToEnableFsverity,
     }
 
     /**
diff --git a/compos/composd/src/instance_manager.rs b/compos/composd/src/instance_manager.rs
index 98d4a1b..2ce12f8 100644
--- a/compos/composd/src/instance_manager.rs
+++ b/compos/composd/src/instance_manager.rs
@@ -19,16 +19,16 @@
 
 use crate::instance_starter::{CompOsInstance, InstanceStarter};
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice;
-use anyhow::{bail, Result};
+use anyhow::{anyhow, bail, Context, Result};
 use binder::Strong;
 use compos_common::compos_client::{VmCpuTopology, VmParameters};
 use compos_common::{CURRENT_INSTANCE_DIR, TEST_INSTANCE_DIR};
+use log::info;
+use rustutils::system_properties;
+use std::str::FromStr;
 use std::sync::{Arc, Mutex, Weak};
 use virtualizationservice::IVirtualizationService::IVirtualizationService;
 
-// Enough memory to complete odrefresh in the VM.
-const VM_MEMORY_MIB: i32 = 1024;
-
 pub struct InstanceManager {
     service: Strong<dyn IVirtualizationService>,
     state: Mutex<State>,
@@ -81,12 +81,33 @@
     // number of dex2oat threads.
     let cpu_topology = VmCpuTopology::MatchHost;
     let task_profiles = vec!["SCHED_SP_COMPUTE".to_string()];
-    Ok(VmParameters {
-        cpu_topology,
-        task_profiles,
-        memory_mib: Some(VM_MEMORY_MIB),
-        ..Default::default()
-    })
+    let memory_mib = Some(compos_memory_mib()?);
+    Ok(VmParameters { cpu_topology, task_profiles, memory_mib, ..Default::default() })
+}
+
+fn compos_memory_mib() -> Result<i32> {
+    // Enough memory to complete odrefresh in the VM, for older versions of ART that don't set the
+    // property explicitly.
+    const DEFAULT_MEMORY_MIB: u32 = 400;
+
+    let art_requested_mib =
+        read_property("composd.vm.art.memory_mib.config")?.unwrap_or(DEFAULT_MEMORY_MIB);
+
+    let vm_adjustment_mib = read_property("composd.vm.vendor.memory_mib.config")?.unwrap_or(0);
+
+    info!(
+        "Compilation VM memory: ART requests {art_requested_mib} MiB, \
+        VM adjust is {vm_adjustment_mib}"
+    );
+    art_requested_mib
+        .checked_add_signed(vm_adjustment_mib)
+        .and_then(|x| x.try_into().ok())
+        .context("Invalid vm memory adjustment")
+}
+
+fn read_property<T: FromStr>(name: &str) -> Result<Option<T>> {
+    let str = system_properties::read(name).context("Failed to read {name}")?;
+    str.map(|s| s.parse().map_err(|_| anyhow!("Invalid {name}: {s}"))).transpose()
 }
 
 // Ensures we only run one instance at a time.
diff --git a/compos/composd/src/odrefresh_task.rs b/compos/composd/src/odrefresh_task.rs
index 3a699ab..a98f50d 100644
--- a/compos/composd/src/odrefresh_task.rs
+++ b/compos/composd/src/odrefresh_task.rs
@@ -28,11 +28,16 @@
     CompilationMode::CompilationMode, ICompOsService, OdrefreshArgs::OdrefreshArgs,
 };
 use compos_common::odrefresh::{
-    is_system_property_interesting, ExitCode, ODREFRESH_OUTPUT_ROOT_DIR,
+    is_system_property_interesting, ExitCode, CURRENT_ARTIFACTS_SUBDIR, ODREFRESH_OUTPUT_ROOT_DIR,
+    PENDING_ARTIFACTS_SUBDIR,
 };
+use compos_common::BUILD_MANIFEST_SYSTEM_EXT_APK_PATH;
 use log::{error, info, warn};
+use odsign_proto::odsign_info::OdsignInfo;
+use protobuf::Message;
 use rustutils::system_properties;
-use std::fs::{remove_dir_all, OpenOptions};
+use std::fs::{remove_dir_all, File, OpenOptions};
+use std::os::fd::AsFd;
 use std::os::unix::fs::OpenOptionsExt;
 use std::os::unix::io::{AsRawFd, OwnedFd};
 use std::path::Path;
@@ -103,8 +108,21 @@
 
                 let result = match exit_code {
                     Ok(ExitCode::CompilationSuccess) => {
-                        info!("CompilationSuccess");
-                        callback.onSuccess()
+                        if compilation_mode == CompilationMode::TEST_COMPILE {
+                            info!("Compilation success");
+                            callback.onSuccess()
+                        } else {
+                            // compos.info is generated only during NORMAL_COMPILE
+                            if let Err(e) = enable_fsverity_to_all() {
+                                let message =
+                                    format!("Unexpected failure when enabling fs-verity: {:?}", e);
+                                error!("{}", message);
+                                callback.onFailure(FailureReason::FailedToEnableFsverity, &message)
+                            } else {
+                                info!("Compilation success, fs-verity enabled");
+                                callback.onSuccess()
+                            }
+                        }
                     }
                     Ok(exit_code) => {
                         let message = format!("Unexpected odrefresh result: {:?}", exit_code);
@@ -161,13 +179,20 @@
     let output_dir_raw_fd = output_dir_fd.as_raw_fd();
     let staging_dir_raw_fd = staging_dir_fd.as_raw_fd();
 
-    // Get the /system_ext FD differently because it may not exist.
-    let (system_ext_dir_raw_fd, ro_dir_fds) =
-        if let Ok(system_ext_dir_fd) = open_dir(Path::new("/system_ext")) {
-            (system_ext_dir_fd.as_raw_fd(), vec![system_dir_fd, system_ext_dir_fd])
-        } else {
-            (-1, vec![system_dir_fd])
-        };
+    // When the VM starts, it starts with or without mouting the extra build manifest APK from
+    // /system_ext. Later on request (here), we need to pass the directory FD of /system_ext, but
+    // only if the VM is configured to need it.
+    //
+    // It is possible to plumb the information from ComposClient to here, but it's extra complexity
+    // and feel slightly weird to encode the VM's state to the task itself, as it is a request to
+    // the VM.
+    let need_system_ext = Path::new(BUILD_MANIFEST_SYSTEM_EXT_APK_PATH).exists();
+    let (system_ext_dir_raw_fd, ro_dir_fds) = if need_system_ext {
+        let system_ext_dir_fd = open_dir(Path::new("/system_ext"))?;
+        (system_ext_dir_fd.as_raw_fd(), vec![system_dir_fd, system_ext_dir_fd])
+    } else {
+        (-1, vec![system_dir_fd])
+    };
 
     // Spawn a fd_server to serve the FDs.
     let fd_server_config = FdServerConfig {
@@ -197,6 +222,31 @@
     ExitCode::from_i32(exit_code.into())
 }
 
+/// Enable fs-verity to output artifacts according to compos.info in the pending directory. Any
+/// error before the completion will just abort, leaving the previous files enabled.
+fn enable_fsverity_to_all() -> Result<()> {
+    let odrefresh_current_dir = Path::new(ODREFRESH_OUTPUT_ROOT_DIR).join(CURRENT_ARTIFACTS_SUBDIR);
+    let pending_dir = Path::new(ODREFRESH_OUTPUT_ROOT_DIR).join(PENDING_ARTIFACTS_SUBDIR);
+    let mut reader =
+        File::open(&pending_dir.join("compos.info")).context("Failed to open compos.info")?;
+    let compos_info = OdsignInfo::parse_from_reader(&mut reader).context("Failed to parse")?;
+
+    for path_str in compos_info.file_hashes.keys() {
+        // Need to rebase the directory on to compos-pending first
+        if let Ok(relpath) = Path::new(path_str).strip_prefix(&odrefresh_current_dir) {
+            let path = pending_dir.join(relpath);
+            let file = File::open(&path).with_context(|| format!("Failed to open {:?}", path))?;
+            // We don't expect error. But when it happens, don't bother handle it here. For
+            // simplicity, just let odsign do the regular check.
+            fsverity::enable(file.as_fd())
+                .with_context(|| format!("Failed to enable fs-verity to {:?}", path))?;
+        } else {
+            warn!("Skip due to unexpected path: {}", path_str);
+        }
+    }
+    Ok(())
+}
+
 /// Returns an `OwnedFD` of the directory.
 fn open_dir(path: &Path) -> Result<OwnedFd> {
     Ok(OwnedFd::from(
diff --git a/compos/service/java/com/android/server/compos/IsolatedCompilationJobService.java b/compos/service/java/com/android/server/compos/IsolatedCompilationJobService.java
index 479ae7f..933ac7a 100644
--- a/compos/service/java/com/android/server/compos/IsolatedCompilationJobService.java
+++ b/compos/service/java/com/android/server/compos/IsolatedCompilationJobService.java
@@ -234,6 +234,10 @@
                     result = IsolatedCompilationMetrics.RESULT_UNEXPECTED_COMPILATION_RESULT;
                     break;
 
+                case ICompilationTaskCallback.FailureReason.FailedToEnableFsverity:
+                    result = IsolatedCompilationMetrics.RESULT_FAILED_TO_ENABLE_FSVERITY;
+                    break;
+
                 default:
                     result = IsolatedCompilationMetrics.RESULT_UNKNOWN_FAILURE;
                     break;
diff --git a/compos/service/java/com/android/server/compos/IsolatedCompilationMetrics.java b/compos/service/java/com/android/server/compos/IsolatedCompilationMetrics.java
index e333198..f7799a4 100644
--- a/compos/service/java/com/android/server/compos/IsolatedCompilationMetrics.java
+++ b/compos/service/java/com/android/server/compos/IsolatedCompilationMetrics.java
@@ -36,9 +36,17 @@
 
     // TODO(b/218525257): Move the definition of these enums to atoms.proto
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({RESULT_UNKNOWN, RESULT_SUCCESS, RESULT_UNKNOWN_FAILURE, RESULT_FAILED_TO_START,
-            RESULT_JOB_CANCELED, RESULT_COMPILATION_FAILED, RESULT_UNEXPECTED_COMPILATION_RESULT,
-            RESULT_COMPOSD_DIED})
+    @IntDef({
+        RESULT_UNKNOWN,
+        RESULT_SUCCESS,
+        RESULT_UNKNOWN_FAILURE,
+        RESULT_FAILED_TO_START,
+        RESULT_JOB_CANCELED,
+        RESULT_COMPILATION_FAILED,
+        RESULT_UNEXPECTED_COMPILATION_RESULT,
+        RESULT_COMPOSD_DIED,
+        RESULT_FAILED_TO_ENABLE_FSVERITY
+    })
     public @interface CompilationResult {}
 
     // Keep this in sync with Result enum in IsolatedCompilationEnded in
@@ -59,6 +67,9 @@
             .ISOLATED_COMPILATION_ENDED__COMPILATION_RESULT__RESULT_UNEXPECTED_COMPILATION_RESULT;
     public static final int RESULT_COMPOSD_DIED =
             ArtStatsLog.ISOLATED_COMPILATION_ENDED__COMPILATION_RESULT__RESULT_COMPOSD_DIED;
+    public static final int RESULT_FAILED_TO_ENABLE_FSVERITY =
+            ArtStatsLog
+                    .ISOLATED_COMPILATION_ENDED__COMPILATION_RESULT__RESULT_FAILED_TO_ENABLE_FSVERITY;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SCHEDULING_RESULT_UNKNOWN, SCHEDULING_SUCCESS, SCHEDULING_FAILURE})
diff --git a/docs/debug/tracing.md b/docs/debug/tracing.md
index ebc0ac3..facd9d0 100644
--- a/docs/debug/tracing.md
+++ b/docs/debug/tracing.md
@@ -16,11 +16,13 @@
 * Only boot clock is supported, and there is no way for user space to change the tracing_clock.
 * Hypervisor tracing periodically polls the data from the hypervisor, this is different from the
   regular ftrace instance which pushes the events into the ring buffer.
+* Resetting ring buffers (by clearing the trace file) is only supported when there are no active
+  readers. If the trace file is cleared while there are active readers, then the ring buffers will
+  be cleared after the last reader disconnects.
+* Changing the size of the ring buffer while the tracing session is active is also not supported.
 
 Note: the list above is not exhaustive.
 
-TODO(b/271412868): add more documentation on the user space interface.
-
 ### Perfetto integration
 
 [Perfetto](https://perfetto.dev/docs/) is an open-source stack for performance instrumentation and
@@ -87,6 +89,61 @@
 tracebox -t 15s -b 32mb hyp
 ```
 
+### Analysing traces using SQL
+
+On top of visualisation, Perfetto also provides a SQL interface to analyse traces. More
+documentation is available at https://perfetto.dev/docs/quickstart/trace-analysis and
+https://perfetto.dev/docs/analysis/trace-processor.
+
+Hypervisor events can be queried via `pkvm_hypervisor_events` SQL view. You can load that view by
+calling `SELECT IMPORT("pkvm.hypervisor");`, e.g.:
+
+```sql
+SELECT IMPORT("pkvm.hypervisor");
+SELECT * FROM pkvm_hypervisor_events limit 5;
+```
+
+Below are some SQL queries that might be useful when analysing hypervisor traces.
+
+**What is the longest time CPU spent in hypervisor, grouped by the reason to enter hypervisor**
+```sql
+SELECT IMPORT("pkvm.hypervisor");
+
+SELECT
+  cpu,
+  reason,
+  ts,
+  dur
+FROM pkvm_hypervisor_events
+JOIN (
+  SELECT
+    MAX(dur) as dur2,
+    cpu as cpu2,
+    reason as reason2
+  FROM pkvm_hypervisor_events
+  GROUP BY 2, 3) AS sc
+ON
+  cpu = sc.cpu2
+  AND dur = sc.dur2
+  AND (reason = sc.reason2 OR (reason IS NULL AND sc.reason2 IS NULL))
+ORDER BY dur desc;
+```
+
+**What are the 10 longest times CPU spent in hypervisor because of host_mem_abort**
+```sql
+SELECT
+  hyp.dur as dur,
+  hyp.ts as ts,
+  EXTRACT_ARG(slices.arg_set_id, 'esr') as esr,
+  EXTRACT_ARG(slices.arg_set_id, 'addr') as addr
+FROM pkvm_hypervisor_events as hyp
+JOIN slices
+ON hyp.slice_id = slices.id
+WHERE hyp.reason = 'host_mem_abort'
+ORDER BY dur desc
+LIMIT 10;
+```
+
 ## Microdroid VM tracing
 
 IMPORTANT: Tracing is only supported for debuggable Microdroid VMs.
diff --git a/microdroid/Android.bp b/microdroid/Android.bp
index 0abaf79..de06d01 100644
--- a/microdroid/Android.bp
+++ b/microdroid/Android.bp
@@ -72,8 +72,6 @@
         "apexd.microdroid",
         "debuggerd",
         "linker",
-        "tombstoned.microdroid",
-        "tombstone_transmit.microdroid",
         "cgroups.json",
         "task_profiles.json",
         "public.libraries.android.txt",
@@ -112,13 +110,26 @@
                 "authfs",
                 "authfs_service",
                 "encryptedstore",
-                "microdroid_crashdump_kernel",
                 "microdroid_kexec",
                 "microdroid_manager",
                 "zipfuse",
             ],
         },
     },
+    arch: {
+        // b/273792258: These could be in multilib.lib64 except that
+        // microdroid_crashdump_kernel doesn't exist for riscv64 yet
+        arm64: {
+            deps: [
+                "microdroid_crashdump_kernel",
+            ],
+        },
+        x86_64: {
+            deps: [
+                "microdroid_crashdump_kernel",
+            ],
+        },
+    },
     linker_config_src: "linker.config.json",
     base_dir: "system",
     dirs: microdroid_rootdirs,
diff --git a/microdroid/init.rc b/microdroid/init.rc
index 5187a12..29f8970 100644
--- a/microdroid/init.rc
+++ b/microdroid/init.rc
@@ -35,7 +35,10 @@
     restorecon /mnt/extra-apk
 
     # Wait for apexd to finish activating APEXes before starting more processes.
-    wait_for_prop apexd.status activated
+    # Microdroid starts apexd in VM mode in which apexd doesn't wait for init after setting
+    # apexd.status to activated, but immediately transitions to ready. Therefore, it's not safe to
+    # wait for the activated status, by the time this line is reached it may be already be ready.
+    wait_for_prop apexd.status ready
     perform_apex_config
 
     # Notify to microdroid_manager that perform_apex_config is done.
@@ -123,14 +126,6 @@
     mkdir /data/vendor_de 0771 root root
     mkdir /data/vendor/hardware 0771 root root
 
-    # Start tombstoned early to be able to store tombstones.
-    # microdroid doesn't have anr, but tombstoned requires it
-    mkdir /data/anr 0775 system system
-    mkdir /data/tombstones 0771 system system
-    mkdir /data/vendor/tombstones 0771 root root
-
-    start tombstoned
-
     # For security reasons, /data/local/tmp should always be empty.
     # Do not place files or directories in /data/local/tmp
     mkdir /data/local 0751 root root
@@ -143,15 +138,6 @@
     # Mark boot completed. This will notify microdroid_manager to run payload.
     setprop dev.bootcomplete 1
 
-on property:tombstone_transmit.start=1
-    mkdir /data/tombstones 0771 system system
-    start tombstone_transmit
-
-service tombstone_transmit /system/bin/tombstone_transmit.microdroid -cid 2 -port 2000 -remove_tombstones_after_transmitting
-    user system
-    group system
-    shutdown critical
-
 service apexd-vm /system/bin/apexd --vm
     user root
     group system
diff --git a/microdroid/kdump/kexec.c b/microdroid/kdump/kexec.c
index 8d88951..d3e8e02 100644
--- a/microdroid/kdump/kexec.c
+++ b/microdroid/kdump/kexec.c
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
 #include <sys/syscall.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -53,6 +54,20 @@
     if (syscall(SYS_kexec_file_load, open_checked(KERNEL), open_checked(INITRD), cmdline_len,
                 CMDLINE, KEXEC_FILE_ON_CRASH) == -1) {
         fprintf(stderr, "Failed to load panic kernel: %s\n", strerror(errno));
+        if (errno == EADDRNOTAVAIL) {
+            struct stat st;
+            off_t kernel_size = 0;
+            off_t initrd_size = 0;
+
+            if (stat(KERNEL, &st) == 0) {
+                kernel_size = st.st_size;
+            }
+            if (stat(INITRD, &st) == 0) {
+                initrd_size = st.st_size;
+            }
+            fprintf(stderr, "Image size too big? %s:%ld bytes, %s:%ld bytes", KERNEL, kernel_size,
+                    INITRD, initrd_size);
+        }
         return 1;
     }
     return 0;
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index fa96bf4..ffa2e45 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -81,7 +81,6 @@
 const ZIPFUSE_BIN: &str = "/system/bin/zipfuse";
 
 const APEX_CONFIG_DONE_PROP: &str = "apex_config.done";
-const TOMBSTONE_TRANSMIT_DONE_PROP: &str = "tombstone_transmit.init_done";
 const DEBUGGABLE_PROP: &str = "ro.boot.microdroid.debuggable";
 
 // SYNC WITH virtualizationservice/src/crosvm.rs
@@ -423,12 +422,11 @@
 
     setup_config_sysprops(&config)?;
 
-    // Start tombstone_transmit if enabled
+    // Set export_tombstones if enabled
     if should_export_tombstones(&config) {
-        system_properties::write("tombstone_transmit.start", "1")
-            .context("set tombstone_transmit.start")?;
-    } else {
-        control_service("stop", "tombstoned")?;
+        // This property is read by tombstone_handler.
+        system_properties::write("microdroid_manager.export_tombstones.enabled", "1")
+            .context("set microdroid_manager.export_tombstones.enabled")?;
     }
 
     // Wait until zipfuse has mounted the APKs so we can access the payload
@@ -448,20 +446,10 @@
     system_properties::write("microdroid_manager.init_done", "1")
         .context("set microdroid_manager.init_done")?;
 
-    // Wait for tombstone_transmit to init
-    if should_export_tombstones(&config) {
-        wait_for_tombstone_transmit_done()?;
-    }
-
     info!("boot completed, time to run payload");
     exec_task(task, service).context("Failed to run payload")
 }
 
-fn control_service(action: &str, service: &str) -> Result<()> {
-    system_properties::write(&format!("ctl.{}", action), service)
-        .with_context(|| format!("Failed to {} {}", action, service))
-}
-
 struct ApkDmverityArgument<'a> {
     apk: &'a str,
     idsig: &'a str,
@@ -733,11 +721,6 @@
     wait_for_property_true(APEX_CONFIG_DONE_PROP).context("Failed waiting for apex config done")
 }
 
-fn wait_for_tombstone_transmit_done() -> Result<()> {
-    wait_for_property_true(TOMBSTONE_TRANSMIT_DONE_PROP)
-        .context("Failed waiting for tombstone transmit done")
-}
-
 fn wait_for_property_true(property_name: &str) -> Result<()> {
     let mut prop = PropertyWatcher::new(property_name)?;
     loop {
diff --git a/tests/benchmark/AndroidTest.xml b/tests/benchmark/AndroidTest.xml
index 0214cd9..29bc95a 100644
--- a/tests/benchmark/AndroidTest.xml
+++ b/tests/benchmark/AndroidTest.xml
@@ -25,6 +25,11 @@
     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
         <option name="force-root" value="true" />
     </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="push" value="perf-setup.sh->/data/local/tmp/perf-setup.sh" />
+        <option name="post-push" value="chmod 755 /data/local/tmp/perf-setup.sh;/data/local/tmp/perf-setup.sh" />
+        <option name="cleanup" value="true" />
+    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.microdroid.benchmark" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
diff --git a/tests/hostside/Android.bp b/tests/hostside/Android.bp
index 78500af..6330b20 100644
--- a/tests/hostside/Android.bp
+++ b/tests/hostside/Android.bp
@@ -23,17 +23,17 @@
 }
 
 genrule {
-    name: "test_avf_debug_policy_with_console_output",
+    name: "test_avf_debug_policy_with_log.dtbo",
     defaults: ["test_avf_debug_policy_overlay"],
-    srcs: ["assets/avf_debug_policy_with_console_output.dts"],
-    out: ["avf_debug_policy_with_console_output.dtbo"],
+    srcs: ["assets/avf_debug_policy_with_log.dts"],
+    out: ["avf_debug_policy_with_log.dtbo"],
 }
 
 genrule {
-    name: "test_avf_debug_policy_without_console_output",
+    name: "test_avf_debug_policy_without_log.dtbo",
     defaults: ["test_avf_debug_policy_overlay"],
-    srcs: ["assets/avf_debug_policy_without_console_output.dts"],
-    out: ["avf_debug_policy_without_console_output.dtbo"],
+    srcs: ["assets/avf_debug_policy_without_log.dts"],
+    out: ["avf_debug_policy_without_log.dtbo"],
 }
 
 genrule {
@@ -76,8 +76,8 @@
         ":pvmfw_test",
         ":test_avf_debug_policy_with_ramdump",
         ":test_avf_debug_policy_without_ramdump",
-        ":test_avf_debug_policy_with_console_output",
-        ":test_avf_debug_policy_without_console_output",
+        ":test_avf_debug_policy_with_log.dtbo",
+        ":test_avf_debug_policy_without_log.dtbo",
         ":test_avf_debug_policy_with_adb",
         ":test_avf_debug_policy_without_adb",
         "assets/bcc.dat",
diff --git a/tests/hostside/assets/avf_debug_policy_with_console_output.dts b/tests/hostside/assets/avf_debug_policy_with_log.dts
similarity index 100%
rename from tests/hostside/assets/avf_debug_policy_with_console_output.dts
rename to tests/hostside/assets/avf_debug_policy_with_log.dts
diff --git a/tests/hostside/assets/avf_debug_policy_without_console_output.dts b/tests/hostside/assets/avf_debug_policy_without_log.dts
similarity index 100%
rename from tests/hostside/assets/avf_debug_policy_without_console_output.dts
rename to tests/hostside/assets/avf_debug_policy_without_log.dts
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 20a6045..a7f7906 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
@@ -67,6 +67,8 @@
 
         // remove any leftover files under test root
         android.tryRun("rm", "-rf", TEST_ROOT + "*");
+
+        android.tryRun("mkdir " + TEST_ROOT);
     }
 
     public static void cleanUpVirtualizationTestSetup(ITestDevice androidDevice)
diff --git a/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java b/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java
index 10f7003..0d64442 100644
--- a/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java
+++ b/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java
@@ -23,6 +23,7 @@
 
 import static org.junit.Assume.assumeTrue;
 import static org.junit.Assume.assumeFalse;
+import static org.junit.Assert.assertThrows;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -31,8 +32,9 @@
 import com.android.microdroid.test.host.MicrodroidHostTestCaseBase;
 import com.android.microdroid.test.host.Pvmfw;
 import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.TestDevice;
+import com.android.tradefed.device.DeviceRuntimeException;
 import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.device.TestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.util.CommandStatus;
 import com.android.tradefed.util.CommandResult;
@@ -68,6 +70,9 @@
     @NonNull private static final String CUSTOM_PVMFW_IMG_PATH = TEST_ROOT + PVMFW_FILE_NAME;
     @NonNull private static final String CUSTOM_PVMFW_IMG_PATH_PROP = "hypervisor.pvmfw.path";
 
+    @NonNull
+    private static final String AVF_DEBUG_POLICY_ADB_DT_PROP_PATH = "/avf/guest/microdroid/adb";
+
     @NonNull private static final String MICRODROID_CMDLINE_PATH = "/proc/cmdline";
     @NonNull private static final String MICRODROID_DT_ROOT_PATH = "/proc/device-tree";
 
@@ -173,8 +178,8 @@
     }
 
     @Test
-    public void testConsoleOutput() throws Exception {
-        Pvmfw pvmfw = createPvmfw("avf_debug_policy_with_console_output.dtbo");
+    public void testLog_consoleOutput() throws Exception {
+        Pvmfw pvmfw = createPvmfw("avf_debug_policy_with_log.dtbo");
         pvmfw.serialize(mCustomPvmfwBinFileOnHost);
 
         CommandResult result = tryLaunchProtectedNonDebuggableVm();
@@ -185,8 +190,20 @@
     }
 
     @Test
-    public void testNoConsoleOutput() throws Exception {
-        Pvmfw pvmfw = createPvmfw("avf_debug_policy_without_console_output.dtbo");
+    public void testLog_logcat() throws Exception {
+        Pvmfw pvmfw = createPvmfw("avf_debug_policy_with_log.dtbo");
+        pvmfw.serialize(mCustomPvmfwBinFileOnHost);
+
+        tryLaunchProtectedNonDebuggableVm();
+
+        assertWithMessage("Microdroid's logcat should have been enabled")
+                .that(hasMicrodroidLogcatOutput())
+                .isTrue();
+    }
+
+    @Test
+    public void testNoLog_noConsoleOutput() throws Exception {
+        Pvmfw pvmfw = createPvmfw("avf_debug_policy_without_log.dtbo");
         pvmfw.serialize(mCustomPvmfwBinFileOnHost);
 
         CommandResult result = tryLaunchProtectedNonDebuggableVm();
@@ -197,6 +214,32 @@
     }
 
     @Test
+    public void testNoLog_noLogcat() throws Exception {
+        Pvmfw pvmfw = createPvmfw("avf_debug_policy_without_log.dtbo");
+        pvmfw.serialize(mCustomPvmfwBinFileOnHost);
+
+        assertThrows(
+                "Microdroid shouldn't be recognized because of missing adb connection",
+                DeviceRuntimeException.class,
+                () ->
+                        launchProtectedVmAndWaitForBootCompleted(
+                                MICRODROID_DEBUG_NONE, BOOT_FAILURE_WAIT_TIME_MS));
+        assertThat(hasMicrodroidLogcatOutput()).isFalse();
+    }
+
+    @Test
+    public void testAdb_boots() throws Exception {
+        assumeTrue(
+                "Skip if host wouldn't install adbd",
+                isDebugPolicyEnabled(AVF_DEBUG_POLICY_ADB_DT_PROP_PATH));
+
+        Pvmfw pvmfw = createPvmfw("avf_debug_policy_with_adb.dtbo");
+        pvmfw.serialize(mCustomPvmfwBinFileOnHost);
+
+        launchProtectedVmAndWaitForBootCompleted(MICRODROID_DEBUG_NONE);
+    }
+
+    @Test
     public void testNoAdb_boots() throws Exception {
         Pvmfw pvmfw = createPvmfw("avf_debug_policy_without_adb.dtbo");
         pvmfw.serialize(mCustomPvmfwBinFileOnHost);
@@ -214,13 +257,23 @@
         Pvmfw pvmfw = createPvmfw("avf_debug_policy_without_adb.dtbo");
         pvmfw.serialize(mCustomPvmfwBinFileOnHost);
 
-        try {
-            launchProtectedVmAndWaitForBootCompleted(
-                    MICRODROID_DEBUG_NONE, BOOT_FAILURE_WAIT_TIME_MS);
-            assertWithMessage("adb shouldn't be available").fail();
-        } catch (Exception e) {
-            // expected exception. passthrough.
+        assertThrows(
+                "Microdroid shouldn't be recognized because of missing adb connection",
+                DeviceRuntimeException.class,
+                () ->
+                        launchProtectedVmAndWaitForBootCompleted(
+                                MICRODROID_DEBUG_NONE, BOOT_FAILURE_WAIT_TIME_MS));
+    }
+
+    private boolean isDebugPolicyEnabled(@NonNull String dtPropertyPath)
+            throws DeviceNotAvailableException {
+        CommandRunner runner = new CommandRunner(mAndroidDevice);
+        CommandResult result =
+                runner.runForResult("xxd", "-p", "/proc/device-tree" + dtPropertyPath);
+        if (result.getStatus() == CommandStatus.SUCCESS) {
+            return HEX_STRING_ONE.equals(result.getStdout().trim());
         }
+        return false;
     }
 
     @NonNull
@@ -245,11 +298,17 @@
                 .build();
     }
 
-    @NonNull
-    private boolean hasConsoleOutput(CommandResult result) throws DeviceNotAvailableException {
+    private boolean hasConsoleOutput(@NonNull CommandResult result)
+            throws DeviceNotAvailableException {
         return result.getStdout().contains("Run /init as init process");
     }
 
+    private boolean hasMicrodroidLogcatOutput() throws DeviceNotAvailableException {
+        CommandResult result =
+                new CommandRunner(mAndroidDevice).runForResult("test", "-s", MICRODROID_LOG_PATH);
+        return result.getExitCode() == 0;
+    }
+
     private ITestDevice launchProtectedVmAndWaitForBootCompleted(String debugLevel)
             throws DeviceNotAvailableException {
         return launchProtectedVmAndWaitForBootCompleted(debugLevel, BOOT_COMPLETE_TIMEOUT_MS);
@@ -271,10 +330,10 @@
     }
 
     // Try to launch protected non-debuggable VM for a while and quit.
-    // Non-debuggable VM doesn't enable adb, so there's no ITestDevice instance of it.
+    // Non-debuggable VM might not enable adb, so there's no ITestDevice instance of it.
     private CommandResult tryLaunchProtectedNonDebuggableVm() throws DeviceNotAvailableException {
         // Can't use MicrodroidBuilder because it expects adb connection
-        // but non-debuggable VM doesn't enable adb.
+        // but non-debuggable VM may not enable adb.
         CommandRunner runner = new CommandRunner(mAndroidDevice);
         runner.run("mkdir", "-p", TEST_ROOT);
         mAndroidDevice.pushFile(mCustomPvmfwBinFileOnHost, TEST_ROOT + PVMFW_FILE_NAME);
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 542f595..b7dbcd8 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -30,6 +30,7 @@
 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
 
 import com.google.common.base.Strings;
 import com.google.common.truth.BooleanSubject;
@@ -56,6 +57,7 @@
 import android.util.Log;
 
 import com.android.compatibility.common.util.CddTest;
+import com.android.compatibility.common.util.VsrTest;
 import com.android.microdroid.test.device.MicrodroidDeviceTestBase;
 import com.android.microdroid.test.vmshare.IVmShareTestService;
 import com.android.microdroid.testservice.IAppCallback;
@@ -635,6 +637,14 @@
 
     @Test
     @CddTest(requirements = {"9.17/C-1-1"})
+    public void testAvfRequiresUpdatableApex() throws Exception {
+        assertWithMessage("Devices that support AVF must also support updatable APEX")
+                .that(SystemProperties.getBoolean("ro.apex.updatable", false))
+                .isTrue();
+    }
+
+    @Test
+    @CddTest(requirements = {"9.17/C-1-1"})
     public void vmmGetAndCreate() throws Exception {
         assumeSupportedDevice();
 
@@ -1951,6 +1961,25 @@
                 .isEqualTo(MS_NOEXEC);
     }
 
+    @Test
+    @VsrTest(requirements = {"VSR-7.1-001.003"})
+    public void kernelVersionRequirement() throws Exception {
+        int firstApiLevel = SystemProperties.getInt("ro.product.first_api_level", 0);
+        assume().withMessage("Skip on devices launched before Android 14 (API level 34)")
+                .that(firstApiLevel)
+                .isAtLeast(34);
+
+        String[] tokens = KERNEL_VERSION.split("\\.");
+        int major = Integer.parseInt(tokens[0]);
+        int minor = Integer.parseInt(tokens[1]);
+
+        // Check kernel version >= 5.15
+        assertTrue(major >= 5);
+        if (major == 5) {
+            assertTrue(minor >= 15);
+        }
+    }
+
     private static class VmShareServiceConnection implements ServiceConnection {
 
         private final CountDownLatch mLatch = new CountDownLatch(1);
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index e015d9d..749d75f 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -725,10 +725,11 @@
 /// user devices (W^X).
 fn check_label_is_allowed(context: &SeContext) -> Result<()> {
     match context.selinux_type()? {
-        | "system_file" // immutable dm-verity protected partition
         | "apk_data_file" // APKs of an installed app
-        | "staging_data_file" // updated/staged APEX images
         | "shell_data_file" // test files created via adb shell
+        | "staging_data_file" // updated/staged APEX images
+        | "system_file" // immutable dm-verity protected partition
+        | "virtualizationservice_data_file" // files created by VS / VirtMgr
          => Ok(()),
         _ => bail!("Label {} is not allowed", context),
     }
diff --git a/virtualizationmanager/src/crosvm.rs b/virtualizationmanager/src/crosvm.rs
index 9db0971..19f5f01 100644
--- a/virtualizationmanager/src/crosvm.rs
+++ b/virtualizationmanager/src/crosvm.rs
@@ -53,6 +53,7 @@
 use rpcbinder::RpcServer;
 
 /// external/crosvm
+use base::AsRawDescriptor;
 use base::UnixSeqpacketListener;
 use vm_control::{BalloonControlCommand, VmRequest, VmResponse};
 
@@ -823,7 +824,9 @@
 
     let control_server_socket = UnixSeqpacketListener::bind(crosvm_control_socket_path)
         .context("failed to create control server")?;
-    command.arg("--socket").arg(add_preserved_fd(&mut preserved_fds, &control_server_socket));
+    command
+        .arg("--socket")
+        .arg(add_preserved_fd(&mut preserved_fds, &control_server_socket.as_raw_descriptor()));
 
     debug!("Preserving FDs {:?}", preserved_fds);
     command.preserved_fds(preserved_fds);
diff --git a/vmbase/README.md b/vmbase/README.md
index 3554ae6..552ac31 100644
--- a/vmbase/README.md
+++ b/vmbase/README.md
@@ -25,28 +25,18 @@
 ```soong
 rust_ffi_static {
     name: "libvmbase_example",
+    defaults: ["vmbase_ffi_defaults"],
     crate_name: "vmbase_example",
     srcs: ["src/main.rs"],
-    edition: "2021",
-    no_stdlibs: true,
-    stdlibs: [
-        "libcompiler_builtins.rust_sysroot",
-        "libcore.rust_sysroot",
-    ],
     rustlibs: [
         "libvmbase",
     ],
-    enabled: false,
-    target: {
-        android_arm64: {
-            enabled: true,
-        },
-    },
 }
 ```
 
-Note that stdlibs must be explicitly specified, as we don't want the normal set of libraries used
-for a C++ binary intended to run in Android userspace.
+`vmbase_ffi_defaults`, among other things, specifies the stdlibs including the `compiler_builtins`
+and `core` crate. These must be explicitly specified as we don't want the normal set of libraries
+used for a C++ binary intended to run in Android userspace.
 
 ### Entry point
 
@@ -139,30 +129,18 @@
 
 ```soong
 cc_binary {
-    name: "vmbase_example_elf",
-    stem: "vmbase_example",
+    name: "vmbase_example",
+    defaults: ["vmbase_elf_defaults"],
     srcs: [
         "idmap.S",
     ],
     static_libs: [
-        "libvmbase_entry",
         "libvmbase_example",
     ],
-    static_executable: true,
-    nocrt: true,
-    system_shared_libs: ["libc"],
-    stl: "none",
     linker_scripts: [
         "image.ld",
         ":vmbase_sections",
     ],
-    installable: false,
-    enabled: false,
-    target: {
-        android_arm64: {
-            enabled: true,
-        },
-    },
 }
 ```
 
@@ -174,9 +152,9 @@
 
 ```soong
 raw_binary {
-    name: "vmbase_example",
-    src: ":vmbase_example_elf",
+    name: "vmbase_example_bin",
     stem: "vmbase_example.bin",
+    src: ":vmbase_example",
     enabled: false,
     target: {
         android_arm64: {