Merge "Change the javadoc comment for FEATURE_VENDOR_MODULES" into main
diff --git a/rialto/Android.bp b/rialto/Android.bp
index 3dfcca1..860e656 100644
--- a/rialto/Android.bp
+++ b/rialto/Android.bp
@@ -103,13 +103,11 @@
"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..da1a063 100644
--- a/rialto/tests/test.rs
+++ b/rialto/tests/test.rs
@@ -16,77 +16,89 @@
use android_system_virtualizationservice::{
aidl::android::system::virtualizationservice::{
- CpuTopology::CpuTopology, DiskImage::DiskImage, Partition::Partition,
- PartitionType::PartitionType, VirtualMachineConfig::VirtualMachineConfig,
+ DiskImage::DiskImage, Partition::Partition, 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::os::unix::io::FromRawFd;
use std::panic;
-use std::thread;
-use std::time::Duration;
-use vmclient::{DeathReason, VmInstance};
-use vsock::{VsockListener, VMADDR_CID_HOST};
+use std::path::PathBuf;
+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<()> {
- boot_rialto_successfully(SIGNED_RIALTO_PATH, VmType::ProtectedVm)
+fn rialto_path(vm_type: VmType) -> &'static str {
+ match vm_type {
+ VmType::ProtectedVm => SIGNED_RIALTO_PATH,
+ VmType::NonProtectedVm => UNSIGNED_RIALTO_PATH,
+ }
}
#[test]
-fn boot_rialto_in_unprotected_vm_successfully() -> Result<()> {
- boot_rialto_successfully(UNSIGNED_RIALTO_PATH, VmType::NonProtectedVm)
+fn process_requests_in_protected_vm() -> Result<()> {
+ let mut vm = start_service_vm(VmType::ProtectedVm)?;
+
+ check_processing_reverse_request(&mut vm)?;
+ Ok(())
}
-fn boot_rialto_successfully(rialto_path: &str, vm_type: VmType) -> Result<()> {
+#[test]
+fn process_requests_in_non_protected_vm() -> Result<()> {
+ let mut vm = start_service_vm(VmType::NonProtectedVm)?;
+
+ check_processing_reverse_request(&mut vm)?;
+ Ok(())
+}
+
+fn check_processing_reverse_request(vm: &mut ServiceVm) -> Result<()> {
+ // 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:?}' for the request '{request:?}'.");
+
+ let expected_response: Vec<u8> = message.as_bytes().iter().rev().cloned().collect();
+ assert_eq!(Response::Reverse(expected_response), response);
+ Ok(())
+}
+
+fn start_service_vm(vm_type: VmType) -> Result<ServiceVm> {
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();
+ ServiceVm::start_vm(vm_instance(vm_type)?, vm_type)
+}
+fn vm_instance(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")?;
- let rialto = File::open(rialto_path).context("Failed to open Rialto kernel binary")?;
- let console = android_log_fd()?;
- let log = android_log_fd()?;
+ let rialto = File::open(rialto_path(vm_type)).context("Failed to open Rialto kernel binary")?;
+ let console = service_vm_manager::android_log_fd()?;
+ let log = service_vm_manager::android_log_fd()?;
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,22 +108,16 @@
}
VmType::NonProtectedVm => vec![],
};
-
let config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
name: String::from("RialtoTest"),
- kernel: None,
- initrd: None,
- params: None,
bootloader: Some(ParcelFileDescriptor::new(rialto)),
disks,
protectedVm: vm_type.is_protected(),
memoryMib: 300,
- cpuTopology: CpuTopology::ONE_CPU,
platformVersion: "~1.0".to_string(),
- gdbPort: 0, // No gdb
..Default::default()
});
- let vm = VmInstance::create(
+ VmInstance::create(
service.as_ref(),
&config,
Some(console),
@@ -119,72 +125,5 @@
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(())
-}
-
-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) };
- // SAFETY: These are new FDs with no previous owner.
- let writer = unsafe { File::from_raw_fd(writer_fd) };
-
- thread::spawn(|| {
- for line in BufReader::new(reader).lines() {
- info!("{}", line.unwrap());
- }
- });
- 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(())
+ .context("Failed to create VM")
}
diff --git a/rustfmt.toml b/rustfmt.toml
deleted file mode 120000
index 475ba8f..0000000
--- a/rustfmt.toml
+++ /dev/null
@@ -1 +0,0 @@
-../../../build/soong/scripts/rustfmt.toml
\ No newline at end of file
diff --git a/rustfmt.toml b/rustfmt.toml
new file mode 100644
index 0000000..aaf15f2
--- /dev/null
+++ b/rustfmt.toml
@@ -0,0 +1,10 @@
+# Android Format Style
+# Should be in sync with build/soong/scripts/rustfmt.toml
+
+edition = "2021"
+use_small_heuristics = "Max"
+newline_style = "Unix"
+
+# Local customizations
+wrap_comments = true
+comment_width = 100
diff --git a/service_vm/client_apk/src/main.rs b/service_vm/client_apk/src/main.rs
index 672dd4a..08d4168 100644
--- a/service_vm/client_apk/src/main.rs
+++ b/service_vm/client_apk/src/main.rs
@@ -41,6 +41,7 @@
fn try_main() -> Result<()> {
info!("Welcome to Service VM Client!");
let csr = b"Hello from Service VM";
+ info!("Sending: {:?}", csr);
let certificate = request_certificate(csr);
info!("Certificate: {:?}", certificate);
Ok(())
diff --git a/service_vm_manager/Android.bp b/service_vm_manager/Android.bp
new file mode 100644
index 0000000..b3618a6
--- /dev/null
+++ b/service_vm_manager/Android.bp
@@ -0,0 +1,24 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_library {
+ name: "libservice_vm_manager",
+ crate_name: "service_vm_manager",
+ defaults: ["avf_build_flags_rust"],
+ srcs: ["src/lib.rs"],
+ prefer_rlib: true,
+ rustlibs: [
+ "android.system.virtualizationservice-rust",
+ "libanyhow",
+ "libciborium",
+ "liblog_rust",
+ "libnix",
+ "libservice_vm_comm",
+ "libvmclient",
+ "libvsock",
+ ],
+ apex_available: [
+ "com.android.virt",
+ ],
+}
diff --git a/service_vm_manager/src/lib.rs b/service_vm_manager/src/lib.rs
new file mode 100644
index 0000000..29eafdd
--- /dev/null
+++ b/service_vm_manager/src/lib.rs
@@ -0,0 +1,206 @@
+// Copyright 2023, 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.
+
+//! This module contains the functions to start, stop and communicate with the
+//! Service VM.
+
+use android_system_virtualizationservice::{
+ aidl::android::system::virtualizationservice::{
+ CpuTopology::CpuTopology, DiskImage::DiskImage,
+ IVirtualizationService::IVirtualizationService, Partition::Partition,
+ PartitionType::PartitionType, VirtualMachineConfig::VirtualMachineConfig,
+ VirtualMachineRawConfig::VirtualMachineRawConfig,
+ },
+ binder::ParcelFileDescriptor,
+};
+use anyhow::{ensure, Context, Result};
+use log::{info, warn};
+use service_vm_comm::{Request, Response, VmType};
+use std::fs::{File, OpenOptions};
+use std::io::{self, BufRead, BufReader, BufWriter, Write};
+use std::os::unix::io::FromRawFd;
+use std::path::{Path, PathBuf};
+use std::thread;
+use std::time::Duration;
+use vmclient::VmInstance;
+use vsock::{VsockListener, VsockStream, VMADDR_CID_HOST};
+
+const VIRT_DATA_DIR: &str = "/data/misc/apexdata/com.android.virt";
+const RIALTO_PATH: &str = "/apex/com.android.virt/etc/rialto.bin";
+const INSTANCE_IMG_NAME: &str = "service_vm_instance.img";
+const INSTANCE_IMG_SIZE_BYTES: i64 = 1 << 20; // 1MB
+const MEMORY_MB: i32 = 300;
+const WRITE_BUFFER_CAPACITY: usize = 512;
+const READ_TIMEOUT: Duration = Duration::from_secs(10);
+const WRITE_TIMEOUT: Duration = Duration::from_secs(10);
+
+/// Service VM.
+pub struct ServiceVm {
+ vsock_stream: VsockStream,
+ /// VmInstance will be dropped when ServiceVm goes out of scope, which will kill the VM.
+ vm: VmInstance,
+}
+
+impl ServiceVm {
+ /// Starts the service VM and returns its instance.
+ /// 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, vm_type.port())?;
+
+ // Starts the service VM.
+ vm.start().context("Failed to start service VM")?;
+ info!("Service VM started");
+
+ // Accepts the connection from the service VM.
+ // TODO(b/299427101): Introduce a timeout for the accept.
+ let (vsock_stream, peer_addr) = vsock_listener.accept().context("Failed to accept")?;
+ info!("Accepted connection {:?}", vsock_stream);
+ ensure!(
+ peer_addr.cid() == u32::try_from(vm.cid()).unwrap(),
+ "The CID of the peer address {} doesn't match the service VM CID {}",
+ peer_addr,
+ vm.cid()
+ );
+ vsock_stream.set_read_timeout(Some(READ_TIMEOUT))?;
+ vsock_stream.set_write_timeout(Some(WRITE_TIMEOUT))?;
+
+ Ok(Self { vsock_stream, vm })
+ }
+
+ /// Processes the request in the service VM.
+ pub fn process_request(&mut self, request: &Request) -> Result<Response> {
+ self.write_request(request)?;
+ self.read_response()
+ }
+
+ /// Sends the request to the service VM.
+ fn write_request(&mut self, request: &Request) -> Result<()> {
+ let mut buffer = BufWriter::with_capacity(WRITE_BUFFER_CAPACITY, &mut self.vsock_stream);
+ ciborium::into_writer(request, &mut buffer)?;
+ buffer.flush().context("Failed to flush the buffer")?;
+ info!("Sent request to the service VM.");
+ Ok(())
+ }
+
+ /// Reads the response from the service VM.
+ fn read_response(&mut self) -> Result<Response> {
+ let response: Response = ciborium::from_reader(&mut self.vsock_stream)
+ .context("Failed to read the response from the service VM")?;
+ info!("Received response from the service VM.");
+ Ok(response)
+ }
+}
+
+impl Drop for ServiceVm {
+ fn drop(&mut self) {
+ // Wait till the service VM finishes releasing all the resources.
+ match self.vm.wait_for_death_with_timeout(Duration::from_secs(10)) {
+ Some(e) => info!("Exit the service VM: {e:?}"),
+ None => warn!("Timed out waiting for service VM exit"),
+ }
+ }
+}
+
+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),
+ writable: true,
+ }];
+ let rialto = File::open(RIALTO_PATH).context("Failed to open Rialto kernel binary")?;
+ let config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
+ name: String::from("Service VM"),
+ bootloader: Some(ParcelFileDescriptor::new(rialto)),
+ disks: vec![DiskImage { image: None, partitions: writable_partitions, writable: true }],
+ protectedVm: true,
+ memoryMib: MEMORY_MB,
+ cpuTopology: CpuTopology::ONE_CPU,
+ platformVersion: "~1.0".to_string(),
+ gdbPort: 0, // No gdb
+ ..Default::default()
+ });
+ let console_out = Some(android_log_fd()?);
+ let console_in = None;
+ let log = Some(android_log_fd()?);
+ let callback = None;
+ VmInstance::create(service.as_ref(), &config, console_out, console_in, log, callback)
+ .context("Failed to create service VM")
+}
+
+/// 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()
+ .read(true)
+ .write(true)
+ .open(instance_img_path)
+ .map(ParcelFileDescriptor::new)?);
+ }
+ let instance_img = OpenOptions::new()
+ .create(true)
+ .read(true)
+ .write(true)
+ .open(instance_img_path)
+ .map(ParcelFileDescriptor::new)?;
+ service.initializeWritablePartition(
+ &instance_img,
+ INSTANCE_IMG_SIZE_BYTES,
+ PartitionType::ANDROID_VM_INSTANCE,
+ )?;
+ Ok(instance_img)
+}
+
+/// This function is only exposed for testing.
+pub 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) };
+ // SAFETY: These are new FDs with no previous owner.
+ let writer = unsafe { File::from_raw_fd(writer_fd) };
+
+ thread::spawn(|| {
+ for line in BufReader::new(reader).lines() {
+ match line {
+ Ok(l) => info!("{}", l),
+ Err(e) => {
+ warn!("Failed to read line: {e:?}");
+ break;
+ }
+ }
+ }
+ });
+ Ok(writer)
+}
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index 781d83f..e79cd5a 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -400,8 +400,9 @@
// Check if partition images are labeled incorrectly. This is to prevent random images
// which are not protected by the Android Verified Boot (e.g. bits downloaded by apps) from
- // being loaded in a pVM. This applies to everything but the instance image in the raw config,
- // and everything but the non-executable, generated partitions in the app config.
+ // being loaded in a pVM. This applies to everything but the instance image in the raw
+ // config, and everything but the non-executable, generated partitions in the app
+ // config.
config
.disks
.iter()
@@ -989,10 +990,10 @@
/// struct.
#[derive(Debug, Default)]
struct State {
- /// The VMs which have been started. When VMs are started a weak reference is added to this list
- /// while a strong reference is returned to the caller over Binder. Once all copies of the
- /// Binder client are dropped the weak reference here will become invalid, and will be removed
- /// from the list opportunistically the next time `add_vm` is called.
+ /// The VMs which have been started. When VMs are started a weak reference is added to this
+ /// list while a strong reference is returned to the caller over Binder. Once all copies of
+ /// the Binder client are dropped the weak reference here will become invalid, and will be
+ /// removed from the list opportunistically the next time `add_vm` is called.
vms: Vec<Weak<VmInstance>>,
}
diff --git a/virtualizationservice/Android.bp b/virtualizationservice/Android.bp
index ac9c1df..c00445d 100644
--- a/virtualizationservice/Android.bp
+++ b/virtualizationservice/Android.bp
@@ -41,6 +41,8 @@
"libvsock",
"libserde",
"libserde_xml_rs",
+ "libservice_vm_comm",
+ "libservice_vm_manager",
],
apex_available: ["com.android.virt"],
}
diff --git a/virtualizationservice/src/main.rs b/virtualizationservice/src/main.rs
index cdb3ac9..9778599 100644
--- a/virtualizationservice/src/main.rs
+++ b/virtualizationservice/src/main.rs
@@ -18,7 +18,6 @@
mod atom;
mod remote_provisioning;
mod rkpvm;
-mod service_vm;
use crate::aidl::{
remove_temporary_dir, BINDER_SERVICE_IDENTIFIER, TEMPORARY_DIRECTORY,
diff --git a/virtualizationservice/src/rkpvm.rs b/virtualizationservice/src/rkpvm.rs
index bb05edd..2c9230b 100644
--- a/virtualizationservice/src/rkpvm.rs
+++ b/virtualizationservice/src/rkpvm.rs
@@ -16,19 +16,18 @@
//! The RKP VM will be recognized and attested by the RKP server periodically and
//! serves as a trusted platform to attest a client VM.
-use crate::service_vm;
-use anyhow::{anyhow, Result};
-use log::info;
-use std::time::Duration;
+use anyhow::{bail, Context, Result};
+use service_vm_comm::{Request, Response};
+use service_vm_manager::ServiceVm;
pub(crate) fn request_certificate(csr: &[u8]) -> Result<Vec<u8>> {
- let vm = service_vm::start()?;
+ let mut vm = ServiceVm::start()?;
- // TODO(b/274441673): The host can send the CSR to the RKP VM for attestation.
- // Wait for VM to finish.
- vm.wait_for_death_with_timeout(Duration::from_secs(10))
- .ok_or_else(|| anyhow!("Timed out waiting for VM exit"))?;
-
- info!("service_vm: Finished getting the certificate");
- Ok([b"Return: ", csr].concat())
+ // TODO(b/271275206): Send the correct request type with client VM's
+ // information to be attested.
+ let request = Request::Reverse(csr.to_vec());
+ match vm.process_request(&request).context("Failed to process request")? {
+ Response::Reverse(cert) => Ok(cert),
+ _ => bail!("Incorrect response type"),
+ }
}
diff --git a/virtualizationservice/src/service_vm.rs b/virtualizationservice/src/service_vm.rs
deleted file mode 100644
index 5a1744f..0000000
--- a/virtualizationservice/src/service_vm.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2023, 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.
-
-//! Service VM.
-
-use android_system_virtualizationservice::{
- aidl::android::system::virtualizationservice::{
- CpuTopology::CpuTopology, DiskImage::DiskImage,
- IVirtualizationService::IVirtualizationService, Partition::Partition,
- PartitionType::PartitionType, VirtualMachineConfig::VirtualMachineConfig,
- VirtualMachineRawConfig::VirtualMachineRawConfig,
- },
- binder::ParcelFileDescriptor,
-};
-use anyhow::{Context, Result};
-use log::info;
-use std::fs::{File, OpenOptions};
-use std::path::Path;
-use vmclient::VmInstance;
-
-const VIRT_DATA_DIR: &str = "/data/misc/apexdata/com.android.virt";
-const RIALTO_PATH: &str = "/apex/com.android.virt/etc/rialto.bin";
-const INSTANCE_IMG_NAME: &str = "service_vm_instance.img";
-const INSTANCE_IMG_SIZE_BYTES: i64 = 1 << 20; // 1MB
-const MEMORY_MB: i32 = 300;
-
-/// Starts the service VM and returns its instance.
-/// 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<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 vm = vm_instance(service.as_ref())?;
-
- vm.start().context("Failed to start service VM")?;
- info!("Service VM started");
- Ok(vm)
-}
-
-fn vm_instance(service: &dyn IVirtualizationService) -> Result<VmInstance> {
- let instance_img = instance_img(service)?;
- let writable_partitions = vec![Partition {
- label: "vm-instance".to_owned(),
- image: Some(instance_img),
- writable: true,
- }];
- let rialto = File::open(RIALTO_PATH).context("Failed to open Rialto kernel binary")?;
- let config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
- name: String::from("Service VM"),
- bootloader: Some(ParcelFileDescriptor::new(rialto)),
- disks: vec![DiskImage { image: None, partitions: writable_partitions, writable: true }],
- protectedVm: true,
- memoryMib: MEMORY_MB,
- cpuTopology: CpuTopology::ONE_CPU,
- platformVersion: "~1.0".to_string(),
- gdbPort: 0, // No gdb
- ..Default::default()
- });
- let console_out = None;
- let console_in = None;
- let log = None;
- let callback = None;
- VmInstance::create(service, &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);
- if instance_img_path.exists() {
- // TODO(b/298174584): Try to recover if the service VM is triggered by rkpd.
- return Ok(OpenOptions::new()
- .read(true)
- .write(true)
- .open(instance_img_path)
- .map(ParcelFileDescriptor::new)?);
- }
- let instance_img = OpenOptions::new()
- .create(true)
- .read(true)
- .write(true)
- .open(instance_img_path)
- .map(ParcelFileDescriptor::new)?;
- service.initializeWritablePartition(
- &instance_img,
- INSTANCE_IMG_SIZE_BYTES,
- PartitionType::ANDROID_VM_INSTANCE,
- )?;
- Ok(instance_img)
-}
diff --git a/vm_payload/include/vm_payload.h b/vm_payload/include/vm_payload.h
index 5cc2d1e..c28cd42 100644
--- a/vm_payload/include/vm_payload.h
+++ b/vm_payload/include/vm_payload.h
@@ -105,10 +105,10 @@
* behalf of the VM by the host app. All data is encrypted using a key known
* only to the VM, so the host cannot decrypt it, but may delete it.
*
- * \return the path to the APK contents, or NULL if no encrypted storage was
- * requested in the VM configuration. If non-null the returned string should not
- * be deleted or freed by the application and remains valid for the lifetime of
- * the VM.
+ * \return the path to the encrypted storage directory, or NULL if no encrypted
+ * storage was requested in the VM configuration. If non-null the returned
+ * string should not be deleted or freed by the application and remains valid
+ * for the lifetime of the VM.
*/
const char* _Nullable AVmPayload_getEncryptedStoragePath(void);