[service-vm] Test service_vm_manager in rialto_test

Test: atest rialto_test
Bug: 299089107
Change-Id: Icdb16699d8c14c7e92ee95dabdb7ab8be01d1d74
diff --git a/rialto/Android.bp b/rialto/Android.bp
index 3dfcca1..0b26ccc 100644
--- a/rialto/Android.bp
+++ b/rialto/Android.bp
@@ -103,13 +103,12 @@
         "android.system.virtualizationservice-rust",
         "libandroid_logger",
         "libanyhow",
-        "libciborium",
         "liblibc",
         "liblog_rust",
         "libnix",
         "libservice_vm_comm",
+        "libservice_vm_manager",
         "libvmclient",
-        "libvsock",
     ],
     data: [
         ":rialto_bin",
diff --git a/rialto/tests/test.rs b/rialto/tests/test.rs
index f7df217..ef01063 100644
--- a/rialto/tests/test.rs
+++ b/rialto/tests/test.rs
@@ -17,27 +17,26 @@
 use android_system_virtualizationservice::{
     aidl::android::system::virtualizationservice::{
         CpuTopology::CpuTopology, DiskImage::DiskImage, Partition::Partition,
-        PartitionType::PartitionType, VirtualMachineConfig::VirtualMachineConfig,
+        VirtualMachineConfig::VirtualMachineConfig,
         VirtualMachineRawConfig::VirtualMachineRawConfig,
     },
     binder::{ParcelFileDescriptor, ProcessState},
 };
-use anyhow::{anyhow, bail, Context, Result};
+use anyhow::{Context, Result};
 use log::info;
 use service_vm_comm::{Request, Response, VmType};
+use service_vm_manager::ServiceVm;
 use std::fs::File;
-use std::io::{self, BufRead, BufReader, BufWriter, Write};
+use std::io::{self, BufRead, BufReader};
 use std::os::unix::io::FromRawFd;
 use std::panic;
+use std::path::PathBuf;
 use std::thread;
-use std::time::Duration;
-use vmclient::{DeathReason, VmInstance};
-use vsock::{VsockListener, VMADDR_CID_HOST};
+use vmclient::VmInstance;
 
 const SIGNED_RIALTO_PATH: &str = "/data/local/tmp/rialto_test/arm64/rialto.bin";
 const UNSIGNED_RIALTO_PATH: &str = "/data/local/tmp/rialto_test/arm64/rialto_unsigned.bin";
 const INSTANCE_IMG_PATH: &str = "/data/local/tmp/rialto_test/arm64/instance.img";
-const INSTANCE_IMG_SIZE: i64 = 1024 * 1024; // 1MB
 
 #[test]
 fn boot_rialto_in_protected_vm_successfully() -> Result<()> {
@@ -53,15 +52,28 @@
     android_logger::init_once(
         android_logger::Config::default().with_tag("rialto").with_min_level(log::Level::Debug),
     );
-
     // Redirect panic messages to logcat.
     panic::set_hook(Box::new(|panic_info| {
         log::error!("{}", panic_info);
     }));
-
     // We need to start the thread pool for Binder to work properly, especially link_to_death.
     ProcessState::start_thread_pool();
 
+    let mut vm = ServiceVm::start_vm(vm_instance(rialto_path, vm_type)?, vm_type)?;
+
+    // TODO(b/292080257): Test with message longer than the receiver's buffer capacity
+    // 1024 bytes once the guest virtio-vsock driver fixes the credit update in recv().
+    let message = "abc".repeat(166);
+    let request = Request::Reverse(message.as_bytes().to_vec());
+    let response = vm.process_request(&request)?;
+    info!("Received response: {response:?}.");
+
+    let expected_response: Vec<u8> = message.as_bytes().iter().rev().cloned().collect();
+    assert_eq!(Response::Reverse(expected_response), response);
+    Ok(())
+}
+
+fn vm_instance(rialto_path: &str, vm_type: VmType) -> Result<VmInstance> {
     let virtmgr =
         vmclient::VirtualizationService::new().context("Failed to spawn VirtualizationService")?;
     let service = virtmgr.connect().context("Failed to connect to VirtualizationService")?;
@@ -72,21 +84,10 @@
 
     let disks = match vm_type {
         VmType::ProtectedVm => {
-            let instance_img = File::options()
-                .create(true)
-                .read(true)
-                .write(true)
-                .truncate(true)
-                .open(INSTANCE_IMG_PATH)?;
-            let instance_img = ParcelFileDescriptor::new(instance_img);
-
-            service
-                .initializeWritablePartition(
-                    &instance_img,
-                    INSTANCE_IMG_SIZE,
-                    PartitionType::ANDROID_VM_INSTANCE,
-                )
-                .context("Failed to initialize instange.img")?;
+            let instance_img = service_vm_manager::instance_img(
+                service.as_ref(),
+                PathBuf::from(INSTANCE_IMG_PATH),
+            )?;
             let writable_partitions = vec![Partition {
                 label: "vm-instance".to_owned(),
                 image: Some(instance_img),
@@ -96,7 +97,6 @@
         }
         VmType::NonProtectedVm => vec![],
     };
-
     let config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
         name: String::from("RialtoTest"),
         kernel: None,
@@ -111,7 +111,7 @@
         gdbPort: 0, // No gdb
         ..Default::default()
     });
-    let vm = VmInstance::create(
+    VmInstance::create(
         service.as_ref(),
         &config,
         Some(console),
@@ -119,29 +119,7 @@
         Some(log),
         None,
     )
-    .context("Failed to create VM")?;
-
-    let check_socket_handle =
-        thread::spawn(move || try_check_socket_connection(vm_type.port()).unwrap());
-
-    vm.start().context("Failed to start VM")?;
-
-    // Wait for VM to finish, and check that it shut down cleanly.
-    let death_reason = vm
-        .wait_for_death_with_timeout(Duration::from_secs(10))
-        .ok_or_else(|| anyhow!("Timed out waiting for VM exit"))?;
-    assert_eq!(death_reason, DeathReason::Shutdown);
-
-    match check_socket_handle.join() {
-        Ok(_) => {
-            info!(
-                "Received the echoed message. \
-                   The socket connection between the host and the service VM works correctly."
-            )
-        }
-        Err(_) => bail!("The socket connection check failed."),
-    }
-    Ok(())
+    .context("Failed to create VM")
 }
 
 fn android_log_fd() -> io::Result<File> {
@@ -159,32 +137,3 @@
     });
     Ok(writer)
 }
-
-fn try_check_socket_connection(port: u32) -> Result<()> {
-    info!("Setting up the listening socket on port {port}...");
-    let listener = VsockListener::bind_with_cid_port(VMADDR_CID_HOST, port)?;
-    info!("Listening on port {port}...");
-
-    let mut vsock_stream =
-        listener.incoming().next().ok_or_else(|| anyhow!("Failed to get vsock_stream"))??;
-    info!("Accepted connection {:?}", vsock_stream);
-    vsock_stream.set_read_timeout(Some(Duration::from_millis(1_000)))?;
-
-    const WRITE_BUFFER_CAPACITY: usize = 512;
-    let mut buffer = BufWriter::with_capacity(WRITE_BUFFER_CAPACITY, vsock_stream.clone());
-
-    // TODO(b/292080257): Test with message longer than the receiver's buffer capacity
-    // 1024 bytes once the guest virtio-vsock driver fixes the credit update in recv().
-    let message = "abc".repeat(166);
-    let request = Request::Reverse(message.as_bytes().to_vec());
-    ciborium::into_writer(&request, &mut buffer)?;
-    buffer.flush()?;
-    info!("Sent request: {request:?}.");
-
-    let response: Response = ciborium::from_reader(&mut vsock_stream)?;
-    info!("Received response: {response:?}.");
-
-    let expected_response: Vec<u8> = message.as_bytes().iter().rev().cloned().collect();
-    assert_eq!(Response::Reverse(expected_response), response);
-    Ok(())
-}
diff --git a/service_vm_manager/src/lib.rs b/service_vm_manager/src/lib.rs
index 86b6575..484b57b 100644
--- a/service_vm_manager/src/lib.rs
+++ b/service_vm_manager/src/lib.rs
@@ -29,7 +29,7 @@
 use service_vm_comm::{Request, Response, VmType};
 use std::fs::{File, OpenOptions};
 use std::io::{BufWriter, Write};
-use std::path::Path;
+use std::path::{Path, PathBuf};
 use std::time::Duration;
 use vmclient::VmInstance;
 use vsock::{VsockListener, VsockStream, VMADDR_CID_HOST};
@@ -55,16 +55,18 @@
     /// The same instance image is used for different VMs.
     /// TODO(b/278858244): Allow only one service VM running at each time.
     pub fn start() -> Result<Self> {
+        let vm = vm_instance()?;
+        Self::start_vm(vm, VmType::ProtectedVm)
+    }
+
+    /// Starts the given VM instance and sets up the vsock connection with it.
+    /// Returns a `ServiceVm` instance.
+    /// This function is exposed for testing.
+    pub fn start_vm(vm: VmInstance, vm_type: VmType) -> Result<Self> {
         // Sets up the vsock server on the host.
-        let vsock_listener =
-            VsockListener::bind_with_cid_port(VMADDR_CID_HOST, VmType::ProtectedVm.port())?;
+        let vsock_listener = VsockListener::bind_with_cid_port(VMADDR_CID_HOST, vm_type.port())?;
 
         // Starts the service VM.
-        let virtmgr = vmclient::VirtualizationService::new().context("Failed to spawn VirtMgr")?;
-        let service = virtmgr.connect().context("Failed to connect to VirtMgr")?;
-        info!("Connected to VirtMgr for service VM");
-
-        let vm = vm_instance(service.as_ref())?;
         vm.start().context("Failed to start service VM")?;
         info!("Service VM started");
 
@@ -118,8 +120,13 @@
     }
 }
 
-fn vm_instance(service: &dyn IVirtualizationService) -> Result<VmInstance> {
-    let instance_img = instance_img(service)?;
+fn vm_instance() -> Result<VmInstance> {
+    let virtmgr = vmclient::VirtualizationService::new().context("Failed to spawn VirtMgr")?;
+    let service = virtmgr.connect().context("Failed to connect to VirtMgr")?;
+    info!("Connected to VirtMgr for service VM");
+
+    let instance_img_path = Path::new(VIRT_DATA_DIR).join(INSTANCE_IMG_NAME);
+    let instance_img = instance_img(service.as_ref(), instance_img_path)?;
     let writable_partitions = vec![Partition {
         label: "vm-instance".to_owned(),
         image: Some(instance_img),
@@ -141,12 +148,16 @@
     let console_in = None;
     let log = None;
     let callback = None;
-    VmInstance::create(service, &config, console_out, console_in, log, callback)
+    VmInstance::create(service.as_ref(), &config, console_out, console_in, log, callback)
         .context("Failed to create service VM")
 }
 
-fn instance_img(service: &dyn IVirtualizationService) -> Result<ParcelFileDescriptor> {
-    let instance_img_path = Path::new(VIRT_DATA_DIR).join(INSTANCE_IMG_NAME);
+/// Returns the file descriptor of the instance image at the given path.
+/// This function is only exposed for testing.
+pub fn instance_img(
+    service: &dyn IVirtualizationService,
+    instance_img_path: PathBuf,
+) -> Result<ParcelFileDescriptor> {
     if instance_img_path.exists() {
         // TODO(b/298174584): Try to recover if the service VM is triggered by rkpd.
         return Ok(OpenOptions::new()