Merge "Convert Port forwarding code to kotlin" into main
diff --git a/android/virtmgr/src/crosvm.rs b/android/virtmgr/src/crosvm.rs
index a90c1ff..096d3b5 100644
--- a/android/virtmgr/src/crosvm.rs
+++ b/android/virtmgr/src/crosvm.rs
@@ -324,7 +324,7 @@
             let tap =
                 if let Some(tap_file) = &config.tap { Some(tap_file.try_clone()?) } else { None };
 
-            run_virtiofs(&config)?;
+            let vhost_fs_devices = run_virtiofs(&config)?;
 
             // If this fails and returns an error, `self` will be left in the `Failed` state.
             let child =
@@ -339,7 +339,13 @@
             let child_clone = child.clone();
             let instance_clone = instance.clone();
             let monitor_vm_exit_thread = Some(thread::spawn(move || {
-                instance_clone.monitor_vm_exit(child_clone, failure_pipe_read, vfio_devices, tap);
+                instance_clone.monitor_vm_exit(
+                    child_clone,
+                    failure_pipe_read,
+                    vfio_devices,
+                    tap,
+                    vhost_fs_devices,
+                );
             }));
 
             if detect_hangup {
@@ -486,6 +492,7 @@
         failure_pipe_read: File,
         vfio_devices: Vec<VfioDevice>,
         tap: Option<File>,
+        vhost_user_devices: Vec<SharedChild>,
     ) {
         let failure_reason_thread = std::thread::spawn(move || {
             // Read the pipe to see if any failure reason is written
@@ -513,6 +520,34 @@
             }
         }
 
+        // In crosvm, when vhost_user frontend is dead, vhost_user backend device will detect and
+        // exit. We can safely wait() for vhost user device after waiting crosvm main
+        // process.
+        for device in vhost_user_devices {
+            match device.wait() {
+                Ok(status) => {
+                    info!("Vhost user device({}) exited with status {}", device.id(), status);
+                    if !status.success() {
+                        if let Some(code) = status.code() {
+                            // vhost_user backend device exit with error code
+                            error!(
+                                "vhost user device({}) exited with error code: {}",
+                                device.id(),
+                                code
+                            );
+                        } else {
+                            // The spawned child process of vhost_user backend device is
+                            // killed by signal
+                            error!("vhost user device({}) killed by signal", device.id());
+                        }
+                    }
+                }
+                Err(e) => {
+                    error!("Error waiting for vhost user device({}) to die: {}", device.id(), e);
+                }
+            }
+        }
+
         let failure_reason = failure_reason_thread.join().expect("failure_reason_thread panic'd");
 
         let mut vm_state = self.vm_state.lock().unwrap();
@@ -915,7 +950,8 @@
     }
 }
 
-fn run_virtiofs(config: &CrosvmConfig) -> io::Result<()> {
+fn run_virtiofs(config: &CrosvmConfig) -> io::Result<Vec<SharedChild>> {
+    let mut devices: Vec<SharedChild> = Vec::new();
     for shared_path in &config.shared_paths {
         if shared_path.app_domain {
             continue;
@@ -947,9 +983,10 @@
 
         let result = SharedChild::spawn(&mut command)?;
         info!("Spawned virtiofs crosvm({})", result.id());
+        devices.push(result);
     }
 
-    Ok(())
+    Ok(devices)
 }
 
 /// Starts an instance of `crosvm` to manage a new VM.
diff --git a/build/debian/build.sh b/build/debian/build.sh
index 613f7d2..3f33ec8 100755
--- a/build/debian/build.sh
+++ b/build/debian/build.sh
@@ -307,9 +307,10 @@
 
 generate_output_package() {
 	fdisk -l "${raw_disk_image}"
-	root_partition_num=1
-	bios_partition_num=14
-	efi_partition_num=15
+	local vm_config="$(realpath $(dirname "$0"))/vm_config.json.${arch}"
+	local root_partition_num=1
+	local bios_partition_num=14
+	local efi_partition_num=15
 
 	pushd ${workdir} > /dev/null
 
@@ -373,7 +374,6 @@
 config_space=${debian_cloud_image}/config_space/${debian_version}
 resources_dir=${debian_cloud_image}/src/debian_cloud_images/resources
 arch="$(uname -m)"
-vm_config="$(realpath $(dirname "$0"))/vm_config.json.${arch}"
 mode=debug
 save_workdir=0
 use_custom_kernel=0
diff --git a/docs/getting_started.md b/docs/getting_started.md
index 0a7cca6..03657ed 100644
--- a/docs/getting_started.md
+++ b/docs/getting_started.md
@@ -9,7 +9,7 @@
 * aosp\_oriole (Pixel 6)
 * aosp\_raven (Pixel 6 Pro)
 * aosp\_felix (Pixel Fold)
-* aosp\_tangopro (Pixel Tablet)
+* aosp\_tangorpro (Pixel Tablet)
 * aosp\_cf\_x86\_64\_phone (Cuttlefish a.k.a. Cloud Android). Follow [this
   instruction](https://source.android.com/docs/setup/create/cuttlefish-use) to
   use.
diff --git a/libs/cstr/rules.mk b/libs/cstr/rules.mk
new file mode 100644
index 0000000..2309c30
--- /dev/null
+++ b/libs/cstr/rules.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 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.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+SRC_DIR := packages/modules/Virtualization/libs/cstr
+
+MODULE_SRCS := $(SRC_DIR)/src/lib.rs
+
+MODULE_CRATE_NAME := cstr
+
+MODULE_RUST_EDITION := 2021
+
+include make/library.mk
diff --git a/libs/libfdt/bindgen/rules.mk b/libs/libfdt/bindgen/rules.mk
new file mode 100644
index 0000000..130a317
--- /dev/null
+++ b/libs/libfdt/bindgen/rules.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 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.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS := $(LOCAL_DIR)/src/lib.rs
+
+MODULE_CRATE_NAME := libfdt_bindgen
+
+MODULE_DEPS += \
+	external/dtc/libfdt \
+
+MODULE_BINDGEN_ALLOW_FUNCTIONS := \
+	fdt_.* \
+
+MODULE_BINDGEN_ALLOW_VARS := \
+	FDT_.* \
+
+MODULE_BINDGEN_ALLOW_TYPES := \
+	fdt_.* \
+
+MODULE_BINDGEN_SRC_HEADER := $(LOCAL_DIR)/fdt.h
+
+include make/library.mk
diff --git a/libs/libfdt/bindgen/src/lib.rs b/libs/libfdt/bindgen/src/lib.rs
new file mode 100644
index 0000000..015132b
--- /dev/null
+++ b/libs/libfdt/bindgen/src/lib.rs
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 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.
+ */
+
+//! # Interface library for libfdt.
+
+#![no_std]
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+include!(env!("BINDGEN_INC_FILE"));
diff --git a/libs/libfdt/rules.mk b/libs/libfdt/rules.mk
new file mode 100644
index 0000000..2b4e470
--- /dev/null
+++ b/libs/libfdt/rules.mk
@@ -0,0 +1,37 @@
+# Copyright (C) 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.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+SRC_DIR := packages/modules/Virtualization/libs/libfdt
+
+MODULE_SRCS := $(SRC_DIR)/src/lib.rs
+
+MODULE_CRATE_NAME := libfdt
+
+MODULE_RUST_EDITION := 2021
+
+MODULE_LIBRARY_DEPS += \
+	external/dtc/libfdt \
+	packages/modules/Virtualization/libs/cstr \
+	packages/modules/Virtualization/libs/libfdt/bindgen \
+	$(call FIND_CRATE,zerocopy) \
+	$(call FIND_CRATE,static_assertions) \
+
+MODULE_RUST_USE_CLIPPY := true
+
+include make/library.mk
diff --git a/tests/hostside/Android.bp b/tests/hostside/Android.bp
index 48e369c..0966c20 100644
--- a/tests/hostside/Android.bp
+++ b/tests/hostside/Android.bp
@@ -2,14 +2,9 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-java_test_host {
-    name: "MicrodroidHostTestCases",
+java_defaults {
+    name: "MicrodroidHostTestCases.default",
     srcs: ["java/**/*.java"],
-    test_suites: [
-        "cts",
-        "general-tests",
-        "pts",
-    ],
     libs: [
         "androidx.annotation_annotation",
         "tradefed",
@@ -21,27 +16,6 @@
         "microdroid_payload_metadata",
     ],
     per_testcase_directory: true,
-    device_common_data: [
-        ":MicrodroidTestApp",
-        ":MicrodroidTestAppUpdated",
-        ":microdroid_general_sepolicy.conf",
-        ":test.com.android.virt.pem",
-        ":test2.com.android.virt.pem",
-        "java/**/goldens/dt_dump_*",
-    ],
-    data_native_bins: [
-        "sepolicy-analyze",
-        // For re-sign test
-        "avbtool",
-        "img2simg",
-        "initrd_bootconfig",
-        "lpmake",
-        "lpunpack",
-        "lz4",
-        "sign_virt_apex",
-        "simg2img",
-        "dtc",
-    ],
     // java_test_host doesn't have data_native_libs but jni_libs can be used to put
     // native modules under ./lib directory.
     // This works because host tools have rpath (../lib and ./lib).
@@ -58,3 +32,78 @@
         "libz",
     ],
 }
+
+DEVICE_DATA = [
+    ":MicrodroidTestApp",
+    ":MicrodroidTestAppUpdated",
+    ":microdroid_general_sepolicy.conf",
+    ":test.com.android.virt.pem",
+    ":test2.com.android.virt.pem",
+    "java/**/goldens/dt_dump_*",
+]
+
+BINS = [
+    "sepolicy-analyze",
+    // For re-sign test
+    "avbtool",
+    "img2simg",
+    "initrd_bootconfig",
+    "lpmake",
+    "lpunpack",
+    "lz4",
+    "sign_virt_apex",
+    "simg2img",
+    "dtc",
+]
+
+java_test_host {
+    name: "MicrodroidHostTestCases",
+    defaults: ["MicrodroidHostTestCases.default"],
+    test_config: "AndroidTest.xml",
+    test_suites: [
+        "general-tests",
+        "pts",
+    ],
+    device_common_data: DEVICE_DATA,
+    data_native_bins: BINS,
+}
+
+java_test_host {
+    name: "MicrodroidHostTestCases.CTS",
+    defaults: ["MicrodroidHostTestCases.default"],
+    test_config: ":MicrodroidHostTestCases.CTS.config",
+    test_suites: ["cts"],
+    device_common_data: DEVICE_DATA,
+    data_native_bins: BINS,
+}
+
+java_test_host {
+    name: "MicrodroidHostTestCases.VTS",
+    defaults: ["MicrodroidHostTestCases.default"],
+    test_config: ":MicrodroidHostTestCases.VTS.config",
+    test_suites: ["vts"],
+    device_common_data: DEVICE_DATA,
+    data_native_bins: BINS,
+}
+
+genrule {
+    name: "MicrodroidHostTestCases.CTS.config",
+    srcs: ["AndroidTest.xml"],
+    out: ["out.xml"],
+    cmd: "sed " +
+        "-e 's/<!-- PLACEHOLDER_FOR_ANNOTATION -->/" +
+        "<option name=\"include-annotation\" value=\"com.android.compatibility.common.util.CddTest\" \\/>/' " +
+        "-e 's/MicrodroidHostTestCases.jar/MicrodroidHostTestCases.CTS.jar/' " +
+        "$(in) > $(out)",
+}
+
+genrule {
+    name: "MicrodroidHostTestCases.VTS.config",
+    srcs: ["AndroidTest.xml"],
+    out: ["out.xml"],
+    cmd: "sed " +
+        "-e 's/<!-- PLACEHOLDER_FOR_ANNOTATION -->/" +
+        "<option name=\"include-annotation\" value=\"com.android.compatibility.common.util.VsrTest\" \\/>/' " +
+        "-e 's/MicrodroidHostTestCases.jar/MicrodroidHostTestCases.VTS.jar/' " +
+        "$(in) > $(out)",
+}
diff --git a/tests/hostside/AndroidTest.xml b/tests/hostside/AndroidTest.xml
index f77def3..c277865 100644
--- a/tests/hostside/AndroidTest.xml
+++ b/tests/hostside/AndroidTest.xml
@@ -32,4 +32,6 @@
     <!-- Controller that will skip the module if a native bridge situation is detected -->
     <!-- For example: module wants to run arm and device is x86 -->
     <object type="module_controller" class="com.android.tradefed.testtype.suite.module.NativeBridgeModuleController" />
+
+    <!-- PLACEHOLDER_FOR_ANNOTATION -->
 </configuration>
diff --git a/tests/vts/Android.bp b/tests/vts/Android.bp
index 35fbcdc..c8e2523 100644
--- a/tests/vts/Android.bp
+++ b/tests/vts/Android.bp
@@ -20,6 +20,7 @@
         "libavf_bindgen",
         "libciborium",
         "liblog_rust",
+        "libhypervisor_props",
         "libscopeguard",
         "libservice_vm_comm",
         "libvsock",
diff --git a/tests/vts/src/vts_libavf_test.rs b/tests/vts/src/vts_libavf_test.rs
index ba38a2e..e30c175 100644
--- a/tests/vts/src/vts_libavf_test.rs
+++ b/tests/vts/src/vts_libavf_test.rs
@@ -177,10 +177,20 @@
 
 #[test]
 fn test_run_rialto_protected() -> Result<()> {
-    run_rialto(true /* protected_vm */)
+    if hypervisor_props::is_protected_vm_supported()? {
+        run_rialto(true /* protected_vm */)
+    } else {
+        info!("pVMs are not supported on device. skipping test");
+        Ok(())
+    }
 }
 
 #[test]
 fn test_run_rialto_non_protected() -> Result<()> {
-    run_rialto(false /* protected_vm */)
+    if hypervisor_props::is_vm_supported()? {
+        run_rialto(false /* protected_vm */)
+    } else {
+        info!("non-pVMs are not supported on device. skipping test");
+        Ok(())
+    }
 }