rialto: Initial commit

Clone of ./vmbase/example with basic setup code.

Test: atest rialto_test
Change-Id: Id3d4e96674c261316e79c020ff0b1bd88f4363ba
diff --git a/rialto/tests/test.rs b/rialto/tests/test.rs
new file mode 100644
index 0000000..6cd3f2f
--- /dev/null
+++ b/rialto/tests/test.rs
@@ -0,0 +1,93 @@
+// Copyright 2022, 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.
+
+//! Integration test for Rialto.
+
+use android_system_virtualizationservice::{
+    aidl::android::system::virtualizationservice::{
+        VirtualMachineConfig::VirtualMachineConfig,
+        VirtualMachineRawConfig::VirtualMachineRawConfig,
+    },
+    binder::{ParcelFileDescriptor, ProcessState},
+};
+use anyhow::{Context, Error};
+use log::info;
+use std::fs::File;
+use std::io::{self, BufRead, BufReader};
+use std::os::unix::io::FromRawFd;
+use std::panic;
+use std::thread;
+use vmclient::{DeathReason, VmInstance};
+
+const RIALTO_PATH: &str = "/data/local/tmp/rialto_test/arm64/rialto.bin";
+
+/// Runs the Rialto VM as an unprotected VM via VirtualizationService.
+#[test]
+fn test_boots() -> Result<(), Error> {
+    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 service = vmclient::connect().context("Failed to find VirtualizationService")?;
+    let rialto = File::open(RIALTO_PATH).context("Failed to open Rialto kernel binary")?;
+    let console = android_log_fd()?;
+    let log = android_log_fd()?;
+
+    let config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
+        kernel: None,
+        initrd: None,
+        params: None,
+        bootloader: Some(ParcelFileDescriptor::new(rialto)),
+        disks: vec![],
+        protectedVm: false,
+        memoryMib: 300,
+        numCpus: 1,
+        cpuAffinity: None,
+        platformVersion: "~1.0".to_string(),
+        taskProfiles: vec![],
+    });
+    let vm = VmInstance::create(service.as_ref(), &config, Some(console), Some(log))
+        .context("Failed to create VM")?;
+
+    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();
+    assert_eq!(death_reason, DeathReason::Shutdown);
+
+    Ok(())
+}
+
+fn android_log_fd() -> io::Result<File> {
+    let (reader_fd, writer_fd) = nix::unistd::pipe()?;
+
+    // SAFETY: These are new FDs with no previous owner.
+    let reader = unsafe { File::from_raw_fd(reader_fd) };
+    let writer = unsafe { File::from_raw_fd(writer_fd) };
+
+    thread::spawn(|| {
+        for line in BufReader::new(reader).lines() {
+            info!("{}", line.unwrap());
+        }
+    });
+    Ok(writer)
+}