Merge changes from topic "custom_smcs_allowlist" into main

* changes:
  Implement permission check for VMs that request tee_services
  vm cli: add --tee_services flag
  virtmngr: get secontext of the caller app
  Add teeServices field to AppConfig & RawConfig
  Propagate RELEASE_AVF_ENABLE_VM_TO_TEE_SERVICES_ALLOWLIST to avf_build_flags_rust
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.java
index 0774bb1..1abba85 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.java
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.java
@@ -32,11 +32,11 @@
 import android.view.View;
 import android.widget.CheckBox;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.android.internal.annotations.VisibleForTesting;
 
 import com.google.android.material.progressindicator.LinearProgressIndicator;
+import com.google.android.material.snackbar.Snackbar;
 
 import java.lang.ref.WeakReference;
 import java.util.concurrent.ExecutorService;
@@ -110,10 +110,10 @@
 
     public void handleCriticalError(Exception e) {
         if (Build.isDebuggable()) {
-            Toast.makeText(
-                            this,
+            Snackbar.make(
+                            findViewById(android.R.id.content),
                             e.getMessage() + ". File a bugreport to go/ferrochrome-bug",
-                            Toast.LENGTH_LONG)
+                            Snackbar.LENGTH_INDEFINITE)
                     .show();
         }
         Log.e(TAG, "Internal error", e);
@@ -189,9 +189,9 @@
 
     @MainThread
     private void handleError(String displayText) {
-        // TODO(b/375542145): Display error with snackbar.
         if (Build.isDebuggable()) {
-            Toast.makeText(this, displayText, Toast.LENGTH_LONG).show();
+            Snackbar.make(findViewById(android.R.id.content), displayText, Snackbar.LENGTH_LONG)
+                    .show();
         }
         setInstallEnabled(true);
     }
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
index ebf6154..691e315 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
@@ -88,7 +88,7 @@
     private AccessibilityManager mAccessibilityManager;
     private ConditionVariable mBootCompleted = new ConditionVariable();
     private static final int POST_NOTIFICATIONS_PERMISSION_REQUEST_CODE = 101;
-    private ActivityResultLauncher<Intent> manageExternalStorageActivityResultLauncher;
+    private ActivityResultLauncher<Intent> mManageExternalStorageActivityResultLauncher;
     private static int diskSizeStep;
 
     @Override
@@ -122,27 +122,17 @@
         readClientCertificate();
         connectToTerminalService();
 
-        manageExternalStorageActivityResultLauncher =
+        mManageExternalStorageActivityResultLauncher =
                 registerForActivityResult(
                         new ActivityResultContracts.StartActivityForResult(),
                         (ActivityResult result) -> {
-                            if (Environment.isExternalStorageManager()) {
-                                Toast.makeText(this, "Storage permission set!", Toast.LENGTH_SHORT)
-                                        .show();
-                            } else {
-                                Toast.makeText(
-                                                this,
-                                                "Storage permission not set",
-                                                Toast.LENGTH_SHORT)
-                                        .show();
-                            }
                             startVm();
                         });
 
         // if installer is launched, it will be handled in onActivityResult
         if (!launchInstaller) {
             if (!Environment.isExternalStorageManager()) {
-                requestStoragePermissions(this, manageExternalStorageActivityResultLauncher);
+                requestStoragePermissions(this, mManageExternalStorageActivityResultLauncher);
             } else {
                 startVm();
             }
@@ -435,7 +425,7 @@
                 finish();
             }
             if (!Environment.isExternalStorageManager()) {
-                requestStoragePermissions(this, manageExternalStorageActivityResultLauncher);
+                requestStoragePermissions(this, mManageExternalStorageActivityResultLauncher);
             } else {
                 startVm();
             }
@@ -550,9 +540,8 @@
             SharedPreferences.Editor editor = sharedPref.edit();
 
             long currentDiskSize = getFilesystemSize(file);
-            // The default partition size is 6G
             long newSizeInBytes = sharedPref.getLong(getString(R.string.preference_disk_size_key),
-                    6L << 30);
+                    roundUpDiskSize(currentDiskSize));
             editor.putLong(getString(R.string.preference_disk_size_key), newSizeInBytes);
             editor.apply();
 
diff --git a/android/TerminalApp/res/values/strings.xml b/android/TerminalApp/res/values/strings.xml
index ca803ec..3448388 100644
--- a/android/TerminalApp/res/values/strings.xml
+++ b/android/TerminalApp/res/values/strings.xml
@@ -83,17 +83,17 @@
     <string name="settings_recovery_title">Recovery</string>
     <!-- Settings menu subtitle for recoverying image [CHAR LIMIT=none] -->
     <string name="settings_recovery_sub_title">Partition Recovery options</string>
-    <!-- Settings menu title for resetting the virtual machine image [CHAR LIMIT=none] -->
+    <!-- Settings menu title for resetting the terminal [CHAR LIMIT=none] -->
     <string name="settings_recovery_reset_title">Change to Initial version</string>
-    <!-- Settings menu subtitle for resetting the virtual machine image [CHAR LIMIT=none] -->
+    <!-- Settings menu subtitle for resetting the terminal [CHAR LIMIT=none] -->
     <string name="settings_recovery_reset_sub_title">Remove all</string>
-    <!-- Dialog title for restarting the terminal [CHAR LIMIT=none] -->
-    <string name="settings_recovery_reset_dialog_title">Reset the virtual machine</string>
-    <!-- Dialog message for restarting the terminal [CHAR LIMIT=none] -->
-    <string name="settings_recovery_reset_dialog_message">Data will be deleted.</string>
-    <!-- Dialog button confirm for restarting the terminal [CHAR LIMIT=16] -->
+    <!-- Dialog title for resetting the terminal [CHAR LIMIT=none] -->
+    <string name="settings_recovery_reset_dialog_title">Reset terminal</string>
+    <!-- Dialog message for resetting the terminal [CHAR LIMIT=none] -->
+    <string name="settings_recovery_reset_dialog_message">Data will be deleted</string>
+    <!-- Dialog button confirm for resetting the terminal [CHAR LIMIT=16] -->
     <string name="settings_recovery_reset_dialog_confirm">Confirm</string>
-    <!-- Dialog button cancel for restarting the terminal [CHAR LIMIT=16] -->
+    <!-- Dialog button cancel for resetting the terminal [CHAR LIMIT=16] -->
     <string name="settings_recovery_reset_dialog_cancel">Cancel</string>
 
     <!-- Notification action button for settings [CHAR LIMIT=none] -->
@@ -101,7 +101,7 @@
     <!-- Notification title for foreground service notification [CHAR LIMIT=none] -->
     <string name="service_notification_title">Terminal is running</string>
     <!-- Notification content for foreground service notification [CHAR LIMIT=none] -->
-    <string name="service_notification_content">Click to open the terminal.</string>
+    <string name="service_notification_content">Click to open the terminal</string>
     <!-- Notification action button for closing the virtual machine [CHAR LIMIT=none] -->
     <string name="service_notification_quit_action">Close</string>
 </resources>
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index e63af24..4538248 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -537,7 +537,13 @@
             clone_or_prepare_logger_fd(console_out_fd, format!("Console({})", cid))?;
         let console_in_fd = console_in_fd.map(clone_file).transpose()?;
         let log_fd = clone_or_prepare_logger_fd(log_fd, format!("Log({})", cid))?;
-        let dump_dt_fd = dump_dt_fd.map(clone_file).transpose()?;
+        let dump_dt_fd = if let Some(fd) = dump_dt_fd {
+            Some(clone_file(fd)?)
+        } else if debug_config.dump_device_tree {
+            Some(prepare_dump_dt_file(&temporary_directory)?)
+        } else {
+            None
+        };
 
         // Counter to generate unique IDs for temporary image files.
         let mut next_temporary_image_id = 0;
@@ -1678,6 +1684,16 @@
     Ok(ramdump)
 }
 
+/// Create the empty device tree dump file
+fn prepare_dump_dt_file(temporary_directory: &Path) -> binder::Result<File> {
+    let path = temporary_directory.join("device_tree.dtb");
+    let file = File::create(path)
+        .context("Failed to prepare device tree dump file")
+        .with_log()
+        .or_service_specific_exception(-1)?;
+    Ok(file)
+}
+
 fn is_protected(config: &VirtualMachineConfig) -> bool {
     match config {
         VirtualMachineConfig::RawConfig(config) => config.protectedVm,
diff --git a/android/virtmgr/src/debug_config.rs b/android/virtmgr/src/debug_config.rs
index 74559de..6e2bfef 100644
--- a/android/virtmgr/src/debug_config.rs
+++ b/android/virtmgr/src/debug_config.rs
@@ -30,6 +30,7 @@
 
 const CUSTOM_DEBUG_POLICY_OVERLAY_SYSPROP: &str =
     "hypervisor.virtualizationmanager.debug_policy.path";
+const DUMP_DT_SYSPROP: &str = "hypervisor.virtualizationmanager.dump_device_tree";
 const DEVICE_TREE_EMPTY_TREE_SIZE_BYTES: usize = 100; // rough estimation.
 
 struct DPPath {
@@ -183,6 +184,7 @@
 #[derive(Debug, Default)]
 pub struct DebugConfig {
     pub debug_level: DebugLevel,
+    pub dump_device_tree: bool,
     debug_policy: DebugPolicy,
 }
 
@@ -193,8 +195,13 @@
             info!("Debug policy is disabled");
             Default::default()
         });
+        let dump_dt_sysprop = system_properties::read_bool(DUMP_DT_SYSPROP, false);
+        let dump_device_tree = dump_dt_sysprop.unwrap_or_else(|e| {
+            warn!("Failed to read sysprop {DUMP_DT_SYSPROP}: {e}");
+            false
+        });
 
-        Self { debug_level, debug_policy }
+        Self { debug_level, debug_policy, dump_device_tree }
     }
 
     fn get_debug_policy() -> Option<DebugPolicy> {
diff --git a/build/debian/build.sh b/build/debian/build.sh
index 7fc9035..899e376 100755
--- a/build/debian/build.sh
+++ b/build/debian/build.sh
@@ -11,6 +11,7 @@
 	echo "Options:"
 	echo "-h         Print usage and this help message and exit."
 	echo "-a ARCH    Architecture of the image [default is aarch64]"
+	echo "-r         Release mode build"
 }
 
 check_sudo() {
@@ -21,7 +22,7 @@
 }
 
 parse_options() {
-	while getopts "ha:" option; do
+	while getopts "hra:" option; do
 		case ${option} in
 			h)
 				show_help
@@ -36,6 +37,9 @@
 					debian_arch="amd64"
 				fi
 				;;
+			r)
+				mode=release
+				;;
 			*)
 				echo "Invalid option: $OPTARG"
 				exit
@@ -119,11 +123,17 @@
 
 build_rust_binary_and_copy() {
 	pushd "$(dirname "$0")/../../guest/$1" > /dev/null
+	local release_flag=
+	local artifact_mode=debug
+	if [[ "$mode" == "release" ]]; then
+		release_flag="--release"
+		artifact_mode=release
+	fi
 	RUSTFLAGS="-C linker=${arch}-linux-gnu-gcc" cargo build \
 		--target "${arch}-unknown-linux-gnu" \
-		--target-dir "${workdir}/$1"
+		--target-dir "${workdir}/$1" ${release_flag}
 	mkdir -p "${dst}/files/usr/local/bin/$1"
-	cp "${workdir}/$1/${arch}-unknown-linux-gnu/debug/$1" "${dst}/files/usr/local/bin/$1/AVF"
+	cp "${workdir}/$1/${arch}-unknown-linux-gnu/${artifact_mode}/$1" "${dst}/files/usr/local/bin/$1/AVF"
 	chmod 777 "${dst}/files/usr/local/bin/$1/AVF"
 
 	mkdir -p "${dst}/files/usr/share/doc/$1"
@@ -197,6 +207,7 @@
 resources_dir=${debian_cloud_image}/src/debian_cloud_images/resources
 arch=aarch64
 debian_arch=arm64
+mode=debug
 parse_options "$@"
 check_sudo
 install_prerequisites
diff --git a/build/debian/build_in_container.sh b/build/debian/build_in_container.sh
index fd1a975..d5680e0 100755
--- a/build/debian/build_in_container.sh
+++ b/build/debian/build_in_container.sh
@@ -3,7 +3,8 @@
 if [ -z "$ANDROID_BUILD_TOP" ]; then echo "forgot to source build/envsetup.sh?" && exit 1; fi
 
 arch=aarch64
-while getopts "a:" option; do
+release_flag=
+while getopts "ra:" option; do
   case ${option} in
     a)
       if [[ "$OPTARG" != "aarch64" && "$OPTARG" != "x86_64" ]]; then
@@ -12,6 +13,9 @@
       fi
       arch="$OPTARG"
       ;;
+    r)
+      release_flag="-r"
+      ;;
     *)
       echo "Invalid option: $OPTARG"
       exit
@@ -21,4 +25,4 @@
 
 docker run --privileged -it --workdir /root/Virtualization/build/debian -v \
   "$ANDROID_BUILD_TOP/packages/modules/Virtualization:/root/Virtualization" -v \
-  /dev:/dev ubuntu:22.04 /root/Virtualization/build/debian/build.sh -a "$arch"
+  /dev:/dev ubuntu:22.04 /root/Virtualization/build/debian/build.sh -a "$arch" $release_flag
diff --git a/build/debian/fai_config/files/etc/systemd/system/forwarder_guest_launcher.service/AVF b/build/debian/fai_config/files/etc/systemd/system/forwarder_guest_launcher.service/AVF
index f4c2a24..6dbabea 100644
--- a/build/debian/fai_config/files/etc/systemd/system/forwarder_guest_launcher.service/AVF
+++ b/build/debian/fai_config/files/etc/systemd/system/forwarder_guest_launcher.service/AVF
@@ -4,7 +4,7 @@
 After=network.target
 After=virtiofs_internal.service
 [Service]
-ExecStart=/usr/bin/bash -c '/usr/local/bin/forwarder_guest_launcher --host 192.168.0.1 --grpc_port $(cat /mnt/internal/debian_service_port)'
+ExecStart=/usr/bin/bash -c 'RUST_LOG=debug /usr/local/bin/forwarder_guest_launcher --host 192.168.0.1 --grpc_port $(cat /mnt/internal/debian_service_port)'
 Type=simple
 Restart=on-failure
 RestartSec=1
diff --git a/build/debian/fai_config/files/etc/systemd/system/ttyd.service/AVF b/build/debian/fai_config/files/etc/systemd/system/ttyd.service/AVF
index a2516ff..4a32f2b 100644
--- a/build/debian/fai_config/files/etc/systemd/system/ttyd.service/AVF
+++ b/build/debian/fai_config/files/etc/systemd/system/ttyd.service/AVF
@@ -4,7 +4,7 @@
 After=network.target
 After=virtiofs_internal.service
 [Service]
-ExecStart=/usr/local/bin/ttyd --ssl --ssl-cert /etc/ttyd/server.crt --ssl-key /etc/ttyd/server.key --ssl-ca /mnt/internal/ca.crt -W login -f droid
+ExecStart=/usr/local/bin/ttyd --ssl --ssl-cert /etc/ttyd/server.crt --ssl-key /etc/ttyd/server.key --ssl-ca /mnt/internal/ca.crt -t disableLeaveAlert=true -W login -f droid
 Type=simple
 Restart=always
 User=root
diff --git a/build/debian/fai_config/package_config/AVF b/build/debian/fai_config/package_config/AVF
index 7d86d41..2e55e90 100644
--- a/build/debian/fai_config/package_config/AVF
+++ b/build/debian/fai_config/package_config/AVF
@@ -1,4 +1,5 @@
 PACKAGES install
 
-# Just for testing
-tree
+bpfcc-tools
+linux-headers-generic
+procps
diff --git a/build/debian/image.yaml b/build/debian/image.yaml
index eb42a07..93ec273 100644
--- a/build/debian/image.yaml
+++ b/build/debian/image.yaml
@@ -46,7 +46,7 @@
 vendors:
 - name: nocloud
   faiClasses: [SYSTEM_BOOT, NOCLOUD, LINUX_VARIANT_BASE, TIME_SYSTEMD, AVF]
-  size: 2
+  size: 6
 
 types:
 - name: dev
diff --git a/build/debian/vm_config.json.aarch64 b/build/debian/vm_config.json.aarch64
index bbe590f..d41a29c 100644
--- a/build/debian/vm_config.json.aarch64
+++ b/build/debian/vm_config.json.aarch64
@@ -33,7 +33,6 @@
     "memory_mib": 4096,
     "debuggable": true,
     "console_out": true,
-    "connect_console": true,
     "console_input_device": "ttyS0",
     "network": true
 }
diff --git a/build/debian/vm_config.json.x86_64 b/build/debian/vm_config.json.x86_64
index 1719815..d338080 100644
--- a/build/debian/vm_config.json.x86_64
+++ b/build/debian/vm_config.json.x86_64
@@ -24,7 +24,6 @@
     "memory_mib": 4096,
     "debuggable": true,
     "console_out": true,
-    "connect_console": true,
     "console_input_device": "ttyS0",
     "network": true
 }
diff --git a/build/microdroid/Android.bp b/build/microdroid/Android.bp
index d9e39f0..7f23ae6 100644
--- a/build/microdroid/Android.bp
+++ b/build/microdroid/Android.bp
@@ -139,7 +139,7 @@
             ],
         },
     },
-    linkerconfig: {
+    linker_config: {
         gen_linker_config: true,
         linker_config_srcs: ["linker.config.json"],
     },
diff --git a/docs/debug/README.md b/docs/debug/README.md
index 4b42531..6e51efa 100644
--- a/docs/debug/README.md
+++ b/docs/debug/README.md
@@ -45,6 +45,25 @@
 Note: `--debug full` is the default option when omitted. You need to explicitly
 use `--debug none` to set the debug level to NONE.
 
+### Dump device tree
+
+The VMs device tree can be dumped on creation by adding the `--dump_device_tree`
+argument and passing a path where the device tree gets dumped to, as follows:
+
+```shell
+adb shell /apex/com.android.virt/bin/vm run-microdroid --dump-device-tree PATH
+```
+
+Note: you can set the system property
+`hypervisor.virtualizationmanager.dump_device_tree` to true to always dump the
+device tree to `/data/misc/virtualizationservice/$CID/device_tree.dtb` where
+$CID is the CID of the VM. To set the property, run:
+
+```shell
+adb root
+adb shell setprop hypervisor.virtualizationmanager.dump_device_tree true
+```
+
 ### Debug policy
 
 Debug policy is a per-device property which forcibly enables selected debugging
diff --git a/guest/forwarder_guest_launcher/Cargo.toml b/guest/forwarder_guest_launcher/Cargo.toml
index b7f9eaf..c875484 100644
--- a/guest/forwarder_guest_launcher/Cargo.toml
+++ b/guest/forwarder_guest_launcher/Cargo.toml
@@ -7,7 +7,13 @@
 [dependencies]
 anyhow = "1.0.91"
 clap = { version = "4.5.20", features = ["derive"] }
+csv-async = { version = "1.3.0", features = ["tokio"] }
+env_logger = "0.11.5"
+futures = "0.3.31"
+listeners = "0.2.1"
+log = "0.4.22"
 prost = "0.13.3"
+serde = { version = "1.0.215", features = ["derive"] }
 tokio = { version = "1.40.0", features = ["process", "rt-multi-thread"] }
 tonic = "0.12.3"
 vsock = "0.5.1"
diff --git a/guest/forwarder_guest_launcher/src/main.rs b/guest/forwarder_guest_launcher/src/main.rs
index d753d19..0e06c66 100644
--- a/guest/forwarder_guest_launcher/src/main.rs
+++ b/guest/forwarder_guest_launcher/src/main.rs
@@ -14,18 +14,39 @@
 
 //! Launcher of forwarder_guest
 
-use anyhow::Context;
+use anyhow::{anyhow, Context};
 use clap::Parser;
+use csv_async::AsyncReader;
 use debian_service::debian_service_client::DebianServiceClient;
-use debian_service::QueueOpeningRequest;
+use debian_service::{QueueOpeningRequest, ReportVmActivePortsRequest};
+use futures::stream::StreamExt;
+use log::{debug, error};
+use serde::Deserialize;
+use std::collections::HashSet;
+use std::process::Stdio;
+use tokio::io::BufReader;
 use tokio::process::Command;
-use tonic::transport::Endpoint;
+use tokio::try_join;
+use tonic::transport::{Channel, Endpoint};
 use tonic::Request;
 
 mod debian_service {
     tonic::include_proto!("com.android.virtualization.vmlauncher.proto");
 }
 
+const NON_PREVILEGED_PORT_RANGE_START: i32 = 1024;
+const TCPSTATES_IP_4: i8 = 4;
+const TCPSTATES_STATE_LISTEN: &str = "LISTEN";
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "UPPERCASE")]
+struct TcpStateRow {
+    ip: i8,
+    lport: i32,
+    oldstate: String,
+    newstate: String,
+}
+
 #[derive(Parser)]
 /// Flags for running command
 pub struct Args {
@@ -39,14 +60,9 @@
     grpc_port: String,
 }
 
-#[tokio::main]
-async fn main() -> Result<(), Box<dyn std::error::Error>> {
-    println!("Starting forwarder_guest_launcher");
-    let args = Args::parse();
-    let addr = format!("https://{}:{}", args.host_addr, args.grpc_port);
-
-    let channel = Endpoint::from_shared(addr)?.connect().await?;
-    let mut client = DebianServiceClient::new(channel);
+async fn process_forwarding_request_queue(
+    mut client: DebianServiceClient<Channel>,
+) -> Result<(), Box<dyn std::error::Error>> {
     let cid = vsock::get_local_cid().context("Failed to get CID of VM")?;
     let mut res_stream = client
         .open_forwarding_request_queue(Request::new(QueueOpeningRequest { cid: cid as i32 }))
@@ -58,7 +74,7 @@
             .context("Failed to convert guest_tcp_port as i16")?;
         let vsock_port = response.vsock_port as u32;
 
-        println!(
+        debug!(
             "executing forwarder_guest with guest_tcp_port: {:?}, vsock_port: {:?}",
             &tcp_port, &vsock_port
         );
@@ -70,5 +86,78 @@
             .arg(format!("vsock:2:{}", vsock_port))
             .spawn();
     }
+    Err(anyhow!("process_forwarding_request_queue is terminated").into())
+}
+
+async fn send_active_ports_report(
+    listening_ports: HashSet<i32>,
+    client: &mut DebianServiceClient<Channel>,
+) -> Result<(), Box<dyn std::error::Error>> {
+    let res = client
+        .report_vm_active_ports(Request::new(ReportVmActivePortsRequest {
+            ports: listening_ports.into_iter().collect(),
+        }))
+        .await?
+        .into_inner();
+    if res.success {
+        debug!("Successfully reported active ports to the host");
+    } else {
+        error!("Failure response received from the host for reporting active ports");
+    }
+    Ok(())
+}
+
+async fn report_active_ports(
+    mut client: DebianServiceClient<Channel>,
+) -> Result<(), Box<dyn std::error::Error>> {
+    let mut cmd =
+        Command::new("/usr/sbin/tcpstates-bpfcc").arg("-s").stdout(Stdio::piped()).spawn()?;
+    let stdout = cmd.stdout.take().context("Failed to get stdout of tcpstates")?;
+    let mut csv_reader = AsyncReader::from_reader(BufReader::new(stdout));
+    let header = csv_reader.headers().await?.clone();
+
+    // TODO(b/340126051): Consider using NETLINK_SOCK_DIAG for the optimization.
+    let listeners = listeners::get_all()?;
+    // TODO(b/340126051): Support distinguished port forwarding for ipv6 as well.
+    let mut listening_ports: HashSet<_> = listeners
+        .iter()
+        .map(|x| x.socket)
+        .filter(|x| x.is_ipv4())
+        .map(|x| x.port().into())
+        .filter(|x| *x >= NON_PREVILEGED_PORT_RANGE_START) // Ignore privileged ports
+        .collect();
+    send_active_ports_report(listening_ports.clone(), &mut client).await?;
+
+    let mut records = csv_reader.records();
+    while let Some(record) = records.next().await {
+        let row: TcpStateRow = record?.deserialize(Some(&header))?;
+        if row.ip != TCPSTATES_IP_4 {
+            continue;
+        }
+        match (row.oldstate.as_str(), row.newstate.as_str()) {
+            (_, TCPSTATES_STATE_LISTEN) => {
+                listening_ports.insert(row.lport);
+            }
+            (TCPSTATES_STATE_LISTEN, _) => {
+                listening_ports.remove(&row.lport);
+            }
+            (_, _) => continue,
+        }
+        send_active_ports_report(listening_ports.clone(), &mut client).await?;
+    }
+
+    Err(anyhow!("report_active_ports is terminated").into())
+}
+
+#[tokio::main]
+async fn main() -> Result<(), Box<dyn std::error::Error>> {
+    env_logger::init();
+    debug!("Starting forwarder_guest_launcher");
+    let args = Args::parse();
+    let addr = format!("https://{}:{}", args.host_addr, args.grpc_port);
+    let channel = Endpoint::from_shared(addr)?.connect().await?;
+    let client = DebianServiceClient::new(channel);
+
+    try_join!(process_forwarding_request_queue(client.clone()), report_active_ports(client))?;
     Ok(())
 }
diff --git a/guest/pvmfw/Android.bp b/guest/pvmfw/Android.bp
index a5b7494..477d0a8 100644
--- a/guest/pvmfw/Android.bp
+++ b/guest/pvmfw/Android.bp
@@ -19,6 +19,7 @@
         "libcoset_nostd",
         "libcstr",
         "libdiced_open_dice_nostd",
+        "libhypervisor_backends",
         "liblibfdt_nostd",
         "liblog_rust_nostd",
         "libpvmfw_avb_nostd",
diff --git a/guest/pvmfw/src/device_assignment.rs b/guest/pvmfw/src/device_assignment.rs
index 9b55cff..f37f443 100644
--- a/guest/pvmfw/src/device_assignment.rs
+++ b/guest/pvmfw/src/device_assignment.rs
@@ -28,12 +28,12 @@
 use core::iter::Iterator;
 use core::mem;
 use core::ops::Range;
+// TODO(b/308694211): Use hypervisor_backends::{DeviceAssigningHypervisor, Error} proper for tests.
+#[cfg(not(test))]
+use hypervisor_backends::DeviceAssigningHypervisor;
 use libfdt::{Fdt, FdtError, FdtNode, FdtNodeMut, Phandle, Reg};
 use log::error;
 use log::warn;
-// TODO(b/308694211): Use vmbase::hyp::{DeviceAssigningHypervisor, Error} proper for tests.
-#[cfg(not(test))]
-use vmbase::hyp::DeviceAssigningHypervisor;
 use zerocopy::byteorder::big_endian::U32;
 use zerocopy::FromBytes as _;
 
diff --git a/guest/pvmfw/src/entry.rs b/guest/pvmfw/src/entry.rs
index 64a03cc..ce911b8 100644
--- a/guest/pvmfw/src/entry.rs
+++ b/guest/pvmfw/src/entry.rs
@@ -20,6 +20,7 @@
 use core::mem::{drop, size_of};
 use core::ops::Range;
 use core::slice;
+use hypervisor_backends::get_mmio_guard;
 use log::error;
 use log::info;
 use log::warn;
@@ -28,7 +29,6 @@
 use vmbase::{
     arch::aarch64::min_dcache_line_size,
     configure_heap, console_writeln,
-    hyp::get_mmio_guard,
     layout::{self, crosvm, UART_PAGE_ADDR},
     main,
     memory::{MemoryTracker, MEMORY, SIZE_128KB, SIZE_4KB},
diff --git a/guest/pvmfw/src/fdt.rs b/guest/pvmfw/src/fdt.rs
index 0381f3e..6bbb05e 100644
--- a/guest/pvmfw/src/fdt.rs
+++ b/guest/pvmfw/src/fdt.rs
@@ -30,6 +30,8 @@
 use core::mem::size_of;
 use core::ops::Range;
 use cstr::cstr;
+use hypervisor_backends::get_device_assigner;
+use hypervisor_backends::get_mem_sharer;
 use libfdt::AddressRange;
 use libfdt::CellIterator;
 use libfdt::Fdt;
@@ -46,7 +48,6 @@
 use vmbase::fdt::pci::PciMemoryFlags;
 use vmbase::fdt::pci::PciRangeType;
 use vmbase::fdt::SwiotlbInfo;
-use vmbase::hyp;
 use vmbase::layout::{crosvm::MEM_START, MAX_VIRT_ADDR};
 use vmbase::memory::SIZE_4KB;
 use vmbase::util::RangeExt as _;
@@ -1147,9 +1148,9 @@
 
     let device_assignment = match vm_dtbo {
         Some(vm_dtbo) => {
-            if let Some(hypervisor) = hyp::get_device_assigner() {
+            if let Some(hypervisor) = get_device_assigner() {
                 // TODO(ptosi): Cache the (single?) granule once, in vmbase.
-                let granule = hyp::get_mem_sharer()
+                let granule = get_mem_sharer()
                     .ok_or_else(|| {
                         error!("No MEM_SHARE found during device assignment validation");
                         RebootReason::InternalError
diff --git a/guest/pvmfw/src/memory.rs b/guest/pvmfw/src/memory.rs
index f49d79b..8e8b338 100644
--- a/guest/pvmfw/src/memory.rs
+++ b/guest/pvmfw/src/memory.rs
@@ -23,12 +23,12 @@
 use core::ops::Range;
 use core::result;
 use core::slice;
+use hypervisor_backends::get_mem_sharer;
 use log::debug;
 use log::error;
 use log::info;
 use log::warn;
 use vmbase::{
-    hyp::get_mem_sharer,
     layout::{self, crosvm},
     memory::{PageTable, MEMORY, SIZE_2MB, SIZE_4KB},
     util::align_up,
diff --git a/guest/rialto/Android.bp b/guest/rialto/Android.bp
index 7bcfd54..8afb8ba 100644
--- a/guest/rialto/Android.bp
+++ b/guest/rialto/Android.bp
@@ -14,6 +14,7 @@
         "libciborium_nostd",
         "libcstr",
         "libdiced_open_dice_nostd",
+        "libhypervisor_backends",
         "liblibfdt_nostd",
         "liblog_rust_nostd",
         "libservice_vm_comm_nostd",
diff --git a/guest/rialto/src/error.rs b/guest/rialto/src/error.rs
index ba5f4b0..f021c36 100644
--- a/guest/rialto/src/error.rs
+++ b/guest/rialto/src/error.rs
@@ -17,11 +17,10 @@
 use aarch64_paging::MapError;
 use core::{fmt, result};
 use diced_open_dice::DiceError;
+use hypervisor_backends::Error as HypervisorError;
 use libfdt::FdtError;
 use service_vm_comm::RequestProcessingError;
-use vmbase::{
-    fdt::pci::PciError, hyp::Error as HypervisorError, memory::MemoryTrackerError, virtio::pci,
-};
+use vmbase::{fdt::pci::PciError, memory::MemoryTrackerError, virtio::pci};
 
 pub type Result<T> = result::Result<T, Error>;
 
diff --git a/guest/rialto/src/main.rs b/guest/rialto/src/main.rs
index ec9a76e..244010d 100644
--- a/guest/rialto/src/main.rs
+++ b/guest/rialto/src/main.rs
@@ -32,6 +32,7 @@
 use core::num::NonZeroUsize;
 use core::slice;
 use diced_open_dice::{bcc_handover_parse, DiceArtifacts};
+use hypervisor_backends::get_mem_sharer;
 use libfdt::FdtError;
 use log::{debug, error, info};
 use service_vm_comm::{ServiceVmRequest, VmType};
@@ -47,7 +48,6 @@
     fdt::pci::PciInfo,
     fdt::SwiotlbInfo,
     generate_image_header,
-    hyp::get_mem_sharer,
     layout::{self, crosvm},
     main,
     memory::{MemoryTracker, PageTable, MEMORY, PAGE_SIZE, SIZE_128KB},
diff --git a/guest/trusty/security_vm/launcher/src/main.rs b/guest/trusty/security_vm/launcher/src/main.rs
index bdb4ed8..9611f26 100644
--- a/guest/trusty/security_vm/launcher/src/main.rs
+++ b/guest/trusty/security_vm/launcher/src/main.rs
@@ -15,8 +15,8 @@
 //! A client for trusty security VMs during early boot.
 
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
-    IVirtualizationService::IVirtualizationService, VirtualMachineConfig::VirtualMachineConfig,
-    VirtualMachineRawConfig::VirtualMachineRawConfig,
+    CpuTopology::CpuTopology, IVirtualizationService::IVirtualizationService,
+    VirtualMachineConfig::VirtualMachineConfig, VirtualMachineRawConfig::VirtualMachineRawConfig,
 };
 use android_system_virtualizationservice::binder::{ParcelFileDescriptor, Strong};
 use anyhow::{Context, Result};
@@ -26,7 +26,8 @@
 use vmclient::VmInstance;
 
 #[derive(Parser)]
-struct Args {
+/// Collection of CLI for trusty_security_vm_launcher
+pub struct Args {
     /// Path to the trusty kernel image.
     #[arg(long)]
     kernel: PathBuf,
@@ -42,6 +43,10 @@
     /// Memory size of the VM in MiB
     #[arg(long, default_value_t = 128)]
     memory_size_mib: i32,
+
+    /// CPU Topology exposed to the VM <one-cpu|match-host>
+    #[arg(long, default_value = "one-cpu", value_parser = parse_cpu_topology)]
+    cpu_topology: CpuTopology,
 }
 
 fn get_service() -> Result<Strong<dyn IVirtualizationService>> {
@@ -50,6 +55,14 @@
     virtmgr.connect().context("Failed to connect to VirtualizationService")
 }
 
+fn parse_cpu_topology(s: &str) -> Result<CpuTopology, String> {
+    match s {
+        "one-cpu" => Ok(CpuTopology::ONE_CPU),
+        "match-host" => Ok(CpuTopology::MATCH_HOST),
+        _ => Err(format!("Invalid cpu topology {}", s)),
+    }
+}
+
 fn main() -> Result<()> {
     let args = Args::parse();
 
@@ -63,6 +76,7 @@
         kernel: Some(ParcelFileDescriptor::new(kernel)),
         protectedVm: args.protected,
         memoryMib: args.memory_size_mib,
+        cpuTopology: args.cpu_topology,
         platformVersion: "~1.0".to_owned(),
         // TODO: add instanceId
         ..Default::default()
diff --git a/libs/debian_service/proto/DebianService.proto b/libs/debian_service/proto/DebianService.proto
index a887bf2..bf05ebe 100644
--- a/libs/debian_service/proto/DebianService.proto
+++ b/libs/debian_service/proto/DebianService.proto
@@ -22,6 +22,7 @@
 option java_multiple_files = true;
 
 service DebianService {
+  rpc ReportVmActivePorts (ReportVmActivePortsRequest) returns (ReportVmActivePortsResponse) {}
   rpc ReportVmIpAddr (IpAddr) returns (ReportVmIpAddrResponse) {}
   rpc OpenForwardingRequestQueue (QueueOpeningRequest) returns (stream ForwardingRequestItem) {}
 }
@@ -38,6 +39,14 @@
   bool success = 1;
 }
 
+message ReportVmActivePortsRequest {
+  repeated int32 ports = 1;
+}
+
+message ReportVmActivePortsResponse {
+  bool success = 1;
+}
+
 message ForwardingRequestItem {
   int32 guest_tcp_port = 1;
   int32 vsock_port = 2;
diff --git a/libs/dice/OWNERS b/libs/dice/OWNERS
deleted file mode 100644
index fbc501d..0000000
--- a/libs/dice/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-ascull@google.com
diff --git a/libs/libhypervisor_backends/Android.bp b/libs/libhypervisor_backends/Android.bp
new file mode 100644
index 0000000..b001b8f
--- /dev/null
+++ b/libs/libhypervisor_backends/Android.bp
@@ -0,0 +1,35 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_library_rlib {
+    name: "libhypervisor_backends",
+    crate_name: "hypervisor_backends",
+    defaults: ["avf_build_flags_rust"],
+    edition: "2021",
+    prefer_rlib: true,
+    host_supported: false,
+    no_stdlibs: true,
+    srcs: ["src/lib.rs"],
+    rustlibs: [
+        "libonce_cell_nostd",
+        "libsmccc",
+        "libuuid_nostd",
+    ],
+    enabled: false,
+    target: {
+        android_arm64: {
+            enabled: true,
+            stdlibs: [
+                "libcompiler_builtins.rust_sysroot",
+                "libcore.rust_sysroot",
+            ],
+        },
+    },
+}
+
+dirgroup {
+    name: "trusty_dirgroup_packages_modules_virtualization_libs_libhypervisor_backends",
+    visibility: ["//trusty/vendor/google/aosp/scripts"],
+    dirs: ["."],
+}
diff --git a/libs/libhypervisor_backends/rules.mk b/libs/libhypervisor_backends/rules.mk
new file mode 100644
index 0000000..6fc9dea
--- /dev/null
+++ b/libs/libhypervisor_backends/rules.mk
@@ -0,0 +1,13 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+MODULE := $(LOCAL_DIR)
+MODULE_CRATE_NAME := hypervisor_backends
+MODULE_SRCS := \
+	$(LOCAL_DIR)/src/lib.rs \
+
+MODULE_LIBRARY_DEPS := \
+	trusty/user/base/lib/liballoc-rust \
+	$(call FIND_CRATE,once_cell) \
+	$(call FIND_CRATE,smccc) \
+	$(call FIND_CRATE,uuid) \
+
+include make/library.mk
\ No newline at end of file
diff --git a/libs/libvmbase/src/hyp/error.rs b/libs/libhypervisor_backends/src/error.rs
similarity index 100%
rename from libs/libvmbase/src/hyp/error.rs
rename to libs/libhypervisor_backends/src/error.rs
diff --git a/libs/libvmbase/src/hyp/hypervisor.rs b/libs/libhypervisor_backends/src/hypervisor.rs
similarity index 100%
rename from libs/libvmbase/src/hyp/hypervisor.rs
rename to libs/libhypervisor_backends/src/hypervisor.rs
diff --git a/libs/libvmbase/src/hyp/hypervisor/common.rs b/libs/libhypervisor_backends/src/hypervisor/common.rs
similarity index 98%
rename from libs/libvmbase/src/hyp/hypervisor/common.rs
rename to libs/libhypervisor_backends/src/hypervisor/common.rs
index 8f0e4dc..bfe638f 100644
--- a/libs/libvmbase/src/hyp/hypervisor/common.rs
+++ b/libs/libhypervisor_backends/src/hypervisor/common.rs
@@ -14,7 +14,7 @@
 
 //! This module regroups some common traits shared by all the hypervisors.
 
-use crate::hyp::Result;
+use crate::Result;
 
 /// Trait for the hypervisor.
 pub trait Hypervisor {
diff --git a/libs/libvmbase/src/hyp/hypervisor/geniezone.rs b/libs/libhypervisor_backends/src/hypervisor/geniezone.rs
similarity index 98%
rename from libs/libvmbase/src/hyp/hypervisor/geniezone.rs
rename to libs/libhypervisor_backends/src/hypervisor/geniezone.rs
index fcb9b42..fe56528 100644
--- a/libs/libvmbase/src/hyp/hypervisor/geniezone.rs
+++ b/libs/libhypervisor_backends/src/hypervisor/geniezone.rs
@@ -17,10 +17,7 @@
 use core::fmt::{self, Display, Formatter};
 
 use super::{Hypervisor, MemSharingHypervisor, MmioGuardedHypervisor};
-use crate::{
-    hyp::{Error, Result},
-    memory::page_4kb_of,
-};
+use crate::{mem::page_4kb_of, Error, Result};
 
 use smccc::{
     error::{positive_or_error_64, success_or_error_64},
diff --git a/libs/libvmbase/src/hyp/hypervisor/gunyah.rs b/libs/libhypervisor_backends/src/hypervisor/gunyah.rs
similarity index 100%
rename from libs/libvmbase/src/hyp/hypervisor/gunyah.rs
rename to libs/libhypervisor_backends/src/hypervisor/gunyah.rs
diff --git a/libs/libvmbase/src/hyp/hypervisor/kvm.rs b/libs/libhypervisor_backends/src/hypervisor/kvm.rs
similarity index 98%
rename from libs/libvmbase/src/hyp/hypervisor/kvm.rs
rename to libs/libhypervisor_backends/src/hypervisor/kvm.rs
index 7ed829e..e18c1f4 100644
--- a/libs/libvmbase/src/hyp/hypervisor/kvm.rs
+++ b/libs/libhypervisor_backends/src/hypervisor/kvm.rs
@@ -17,10 +17,7 @@
 use core::fmt::{self, Display, Formatter};
 
 use super::{DeviceAssigningHypervisor, Hypervisor, MemSharingHypervisor, MmioGuardedHypervisor};
-use crate::{
-    hyp::{Error, Result},
-    memory::page_4kb_of,
-};
+use crate::{mem::page_4kb_of, Error, Result};
 
 use smccc::{
     error::{positive_or_error_64, success_or_error_32, success_or_error_64},
diff --git a/libs/libvmbase/src/hyp.rs b/libs/libhypervisor_backends/src/lib.rs
similarity index 94%
rename from libs/libvmbase/src/hyp.rs
rename to libs/libhypervisor_backends/src/lib.rs
index 1cc2ca7..33dc5ad 100644
--- a/libs/libvmbase/src/hyp.rs
+++ b/libs/libhypervisor_backends/src/lib.rs
@@ -14,8 +14,13 @@
 
 //! This library provides wrappers around various hypervisor backends.
 
+#![no_std]
+
+extern crate alloc;
+
 mod error;
 mod hypervisor;
+mod mem;
 
 pub use error::{Error, Result};
 pub use hypervisor::{
diff --git a/libs/libhypervisor_backends/src/mem.rs b/libs/libhypervisor_backends/src/mem.rs
new file mode 100644
index 0000000..ff65c49
--- /dev/null
+++ b/libs/libhypervisor_backends/src/mem.rs
@@ -0,0 +1,28 @@
+// Copyright 2024, 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.
+
+/// The size of a 4KB memory in bytes.
+pub const SIZE_4KB: usize = 4 << 10;
+
+/// 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.
+pub const fn unchecked_align_down(addr: usize, alignment: usize) -> usize {
+    addr & !(alignment - 1)
+}
+
+/// Computes the address of the 4KiB page containing a given address.
+pub const fn page_4kb_of(addr: usize) -> usize {
+    unchecked_align_down(addr, SIZE_4KB)
+}
diff --git a/libs/libvmbase/Android.bp b/libs/libvmbase/Android.bp
index c4e8385..3088633 100644
--- a/libs/libvmbase/Android.bp
+++ b/libs/libvmbase/Android.bp
@@ -81,6 +81,7 @@
         "libbuddy_system_allocator",
         "libcfg_if",
         "libcstr",
+        "libhypervisor_backends",
         "liblibfdt_nostd",
         "liblog_rust_nostd",
         "libonce_cell_nostd",
diff --git a/libs/libvmbase/src/entry.rs b/libs/libvmbase/src/entry.rs
index f442a32..2433722 100644
--- a/libs/libvmbase/src/entry.rs
+++ b/libs/libvmbase/src/entry.rs
@@ -15,7 +15,7 @@
 //! Rust entry point.
 
 use crate::{
-    bionic, console, heap, hyp,
+    bionic, console, heap,
     layout::{UART_ADDRESSES, UART_PAGE_ADDR},
     logger,
     memory::{PAGE_SIZE, SIZE_16KB, SIZE_4KB},
@@ -23,10 +23,11 @@
     rand,
 };
 use core::mem::size_of;
+use hypervisor_backends::{get_mmio_guard, Error};
 use static_assertions::const_assert_eq;
 
-fn try_console_init() -> Result<(), hyp::Error> {
-    if let Some(mmio_guard) = hyp::get_mmio_guard() {
+fn try_console_init() -> Result<(), Error> {
+    if let Some(mmio_guard) = get_mmio_guard() {
         mmio_guard.enroll()?;
 
         // TODO(ptosi): Use MmioSharer::share() to properly track this MMIO_GUARD_MAP.
diff --git a/libs/libvmbase/src/lib.rs b/libs/libvmbase/src/lib.rs
index 630834b..431e899 100644
--- a/libs/libvmbase/src/lib.rs
+++ b/libs/libvmbase/src/lib.rs
@@ -26,7 +26,6 @@
 pub mod fdt;
 pub mod heap;
 mod hvc;
-pub mod hyp;
 pub mod layout;
 pub mod linker;
 pub mod logger;
diff --git a/libs/libvmbase/src/memory/error.rs b/libs/libvmbase/src/memory/error.rs
index 4d08f1e..870e4c9 100644
--- a/libs/libvmbase/src/memory/error.rs
+++ b/libs/libvmbase/src/memory/error.rs
@@ -16,7 +16,7 @@
 
 use core::fmt;
 
-use crate::hyp;
+use hypervisor_backends::Error as HypervisorError;
 
 /// Errors for MemoryTracker operations.
 #[derive(Debug, Clone)]
@@ -38,7 +38,7 @@
     /// Region couldn't be unmapped.
     FailedToUnmap,
     /// Error from the interaction with the hypervisor.
-    Hypervisor(hyp::Error),
+    Hypervisor(HypervisorError),
     /// Failure to set `SHARED_MEMORY`.
     SharedMemorySetFailure,
     /// Failure to set `SHARED_POOL`.
@@ -82,8 +82,8 @@
     }
 }
 
-impl From<hyp::Error> for MemoryTrackerError {
-    fn from(e: hyp::Error) -> Self {
+impl From<HypervisorError> for MemoryTrackerError {
+    fn from(e: HypervisorError) -> Self {
         Self::Hypervisor(e)
     }
 }
diff --git a/libs/libvmbase/src/memory/shared.rs b/libs/libvmbase/src/memory/shared.rs
index 92dd09e..7e5e7e9 100644
--- a/libs/libvmbase/src/memory/shared.rs
+++ b/libs/libvmbase/src/memory/shared.rs
@@ -16,7 +16,6 @@
 
 use super::error::MemoryTrackerError;
 use super::util::virt_to_phys;
-use crate::hyp::{self, get_mem_sharer, get_mmio_guard};
 use crate::layout;
 use crate::util::unchecked_align_down;
 use aarch64_paging::paging::{MemoryRegion as VaRange, VirtualAddress, PAGE_SIZE};
@@ -29,6 +28,7 @@
 use core::ops::Range;
 use core::ptr::NonNull;
 use core::result;
+use hypervisor_backends::{self, get_mem_sharer, get_mmio_guard};
 use log::trace;
 use once_cell::race::OnceBox;
 use spin::mutex::SpinMutex;
@@ -108,7 +108,7 @@
 
 /// Allocates a memory range of at least the given size and alignment that is shared with the host.
 /// Returns a pointer to the buffer.
-pub(crate) fn alloc_shared(layout: Layout) -> hyp::Result<NonNull<u8>> {
+pub(crate) fn alloc_shared(layout: Layout) -> hypervisor_backends::Result<NonNull<u8>> {
     assert_ne!(layout.size(), 0);
     let Some(buffer) = try_shared_alloc(layout) else {
         handle_alloc_error(layout);
@@ -143,7 +143,10 @@
 ///
 /// The memory must have been allocated by `alloc_shared` with the same layout, and not yet
 /// deallocated.
-pub(crate) unsafe fn dealloc_shared(vaddr: NonNull<u8>, layout: Layout) -> hyp::Result<()> {
+pub(crate) unsafe fn dealloc_shared(
+    vaddr: NonNull<u8>,
+    layout: Layout,
+) -> hypervisor_backends::Result<()> {
     SHARED_POOL.get().unwrap().lock().dealloc_aligned(vaddr.as_ptr() as usize, layout);
 
     trace!("Deallocated shared buffer at {vaddr:?} with {layout:?}");
diff --git a/libs/libvmbase/src/memory/tracker.rs b/libs/libvmbase/src/memory/tracker.rs
index acf182f..c1f5d54 100644
--- a/libs/libvmbase/src/memory/tracker.rs
+++ b/libs/libvmbase/src/memory/tracker.rs
@@ -19,7 +19,6 @@
 use super::page_table::{PageTable, MMIO_LAZY_MAP_FLAG};
 use super::shared::{SHARED_MEMORY, SHARED_POOL};
 use crate::dsb;
-use crate::hyp::get_mmio_guard;
 use crate::memory::shared::{MemoryRange, MemorySharer, MmioSharer};
 use crate::util::RangeExt as _;
 use aarch64_paging::paging::{Attributes, Descriptor, MemoryRegion as VaRange, VirtualAddress};
@@ -29,6 +28,7 @@
 use core::num::NonZeroUsize;
 use core::ops::Range;
 use core::result;
+use hypervisor_backends::get_mmio_guard;
 use log::{debug, error};
 use spin::mutex::SpinMutex;
 use tinyvec::ArrayVec;
diff --git a/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/DebianServiceImpl.java b/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/DebianServiceImpl.java
index c64ff77..68ff2ec 100644
--- a/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/DebianServiceImpl.java
+++ b/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/DebianServiceImpl.java
@@ -26,6 +26,8 @@
 import com.android.virtualization.vmlauncher.proto.ForwardingRequestItem;
 import com.android.virtualization.vmlauncher.proto.IpAddr;
 import com.android.virtualization.vmlauncher.proto.QueueOpeningRequest;
+import com.android.virtualization.vmlauncher.proto.ReportVmActivePortsRequest;
+import com.android.virtualization.vmlauncher.proto.ReportVmActivePortsResponse;
 import com.android.virtualization.vmlauncher.proto.ReportVmIpAddrResponse;
 
 import io.grpc.stub.StreamObserver;
@@ -57,20 +59,32 @@
         mCallback = callback;
         mContext = context;
         mSharedPref = mContext.getSharedPreferences(PREFERENCE_FILE_KEY, Context.MODE_PRIVATE);
-        // TODO(b/340126051): Instead of putting fixed value, receive active port list info from the
-        // guest.
-        if (!mSharedPref.contains(PREFERENCE_FORWARDING_PORTS)) {
-            SharedPreferences.Editor editor = mSharedPref.edit();
-            Set<String> ports = new HashSet<>();
-            for (int port = 8080; port < 8090; port++) {
-                ports.add(Integer.toString(port));
+    }
+
+    @Override
+    public void reportVmActivePorts(
+            ReportVmActivePortsRequest request,
+            StreamObserver<ReportVmActivePortsResponse> responseObserver) {
+        Log.d(DebianServiceImpl.TAG, "reportVmActivePorts: " + request.toString());
+
+        SharedPreferences.Editor editor = mSharedPref.edit();
+        Set<String> ports = new HashSet<>();
+        for (int port : request.getPortsList()) {
+            ports.add(Integer.toString(port));
+            if (!mSharedPref.contains(
+                    PREFERENCE_FORWARDING_PORT_IS_ENABLED_PREFIX + Integer.toString(port))) {
                 editor.putBoolean(
                         PREFERENCE_FORWARDING_PORT_IS_ENABLED_PREFIX + Integer.toString(port),
                         false);
             }
-            editor.putStringSet(PREFERENCE_FORWARDING_PORTS, ports);
-            editor.apply();
         }
+        editor.putStringSet(PREFERENCE_FORWARDING_PORTS, ports);
+        editor.apply();
+
+        ReportVmActivePortsResponse reply =
+                ReportVmActivePortsResponse.newBuilder().setSuccess(true).build();
+        responseObserver.onNext(reply);
+        responseObserver.onCompleted();
     }
 
     @Override
diff --git a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
index adab521..03d7fef 100644
--- a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
+++ b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
@@ -1345,9 +1345,8 @@
     }
 
     @Test
-    @Parameters(method = "gkiVersions")
+    @Parameters(method = "osVersions")
     @TestCaseName("{method}_os_{0}")
-    @Ignore("b/360388014") // TODO(b/360388014): fix & re-enable
     public void microdroidDeviceTreeCompat(String os) throws Exception {
         assumeArm64Supported();
         final String configPath = "assets/vm_config.json";
@@ -1374,9 +1373,8 @@
     }
 
     @Test
-    @Parameters(method = "gkiVersions")
+    @Parameters(method = "osVersions")
     @TestCaseName("{method}_os_{0}")
-    @Ignore("b/360388014") // TODO(b/360388014): fix & re-enable
     public void microdroidProtectedDeviceTreeCompat(String os) throws Exception {
         assumeArm64Supported();
         final String configPath = "assets/vm_config.json";
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 917a027..a6c79cb 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -221,6 +221,7 @@
 
     @Test
     @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+    @VsrTest(requirements = {"VSR-7.1-001.006"})
     public void vmAttestationWhenRemoteAttestationIsNotSupported() throws Exception {
         // pVM remote attestation is only supported on protected VMs.
         assumeProtectedVM();
@@ -249,6 +250,7 @@
 
     @Test
     @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+    @VsrTest(requirements = {"VSR-7.1-001.006"})
     public void vmAttestationWithVendorPartitionWhenSupported() throws Exception {
         // pVM remote attestation is only supported on protected VMs.
         assumeProtectedVM();
@@ -267,6 +269,7 @@
 
     @Test
     @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+    @VsrTest(requirements = {"VSR-7.1-001.006"})
     public void vmAttestationWhenRemoteAttestationIsSupported() throws Exception {
         // pVM remote attestation is only supported on protected VMs.
         assumeProtectedVM();