Move VsockFactory into VM client library.

Test: ComposHostTestCases compos_key_tests
Change-Id: I0500c9ad46df4c004f033161ade53b94d3d2afea
This commit is contained in:
Andrew Walbran 2022-05-23 14:47:58 +00:00
parent d0ef400bd1
commit 1072cc0580
7 changed files with 108 additions and 70 deletions

View File

@ -13,7 +13,6 @@ rust_library {
"libanyhow",
"libbinder_common",
"libbinder_rpc_unstable_bindgen",
"libbinder_rs",
"liblog_rust",
"libnum_traits",
"librustutils",

View File

@ -16,7 +16,7 @@
//! Helper for converting Error types to what Binder expects
use binder::{ExceptionCode, Result as BinderResult};
use android_system_virtualizationservice::binder::{ExceptionCode, Result as BinderResult};
use binder_common::new_binder_exception;
use log::warn;
use std::fmt::Debug;

View File

@ -20,7 +20,6 @@ use crate::timeouts::timeouts;
use crate::{COMPOS_APEX_ROOT, COMPOS_DATA_ROOT, COMPOS_VSOCK_PORT, DEFAULT_VM_CONFIG_PATH};
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
DeathReason::DeathReason,
IVirtualMachine::IVirtualMachine,
IVirtualMachineCallback::{BnVirtualMachineCallback, IVirtualMachineCallback},
IVirtualizationService::IVirtualizationService,
VirtualMachineAppConfig::{DebugLevel::DebugLevel, VirtualMachineAppConfig},
@ -29,19 +28,13 @@ use android_system_virtualizationservice::aidl::android::system::virtualizations
use android_system_virtualizationservice::binder::{
BinderFeatures, Interface, ParcelFileDescriptor, Result as BinderResult, Strong,
};
use anyhow::{anyhow, bail, Context, Result};
use binder::{
unstable_api::{new_spibinder, AIBinder},
FromIBinder,
};
use anyhow::{bail, Context, Result};
use compos_aidl_interface::aidl::com::android::compos::ICompOsService::ICompOsService;
use log::{info, warn};
use rustutils::system_properties;
use std::fs::{self, File};
use std::io::{BufRead, BufReader};
use std::num::NonZeroU32;
use std::os::raw;
use std::os::unix::io::IntoRawFd;
use std::path::{Path, PathBuf};
use std::thread;
use vmclient::VmInstance;
@ -159,13 +152,7 @@ impl ComposClient {
/// Create and return an RPC Binder connection to the Comp OS service in the VM.
pub fn get_service(&self) -> Result<Strong<dyn ICompOsService>> {
let mut vsock_factory = VsockFactory::new(&*self.0.vm);
let ibinder = vsock_factory
.connect_rpc_client()
.ok_or_else(|| anyhow!("Failed to connect to CompOS service"))?;
FromIBinder::try_from(ibinder).context("Connecting to CompOS service")
self.0.get_service(COMPOS_VSOCK_PORT).context("Connecting to CompOS service")
}
}
@ -212,56 +199,6 @@ fn want_protected_vm() -> Result<bool> {
bail!("No VM support available")
}
struct VsockFactory<'a> {
vm: &'a dyn IVirtualMachine,
}
impl<'a> VsockFactory<'a> {
fn new(vm: &'a dyn IVirtualMachine) -> Self {
Self { vm }
}
fn connect_rpc_client(&mut self) -> Option<binder::SpIBinder> {
let param = self.as_void_ptr();
unsafe {
// SAFETY: AIBinder returned by RpcPreconnectedClient has correct reference count, and
// the ownership can be safely taken by new_spibinder.
// RpcPreconnectedClient does not take ownership of param, only passing it to
// request_fd.
let binder =
binder_rpc_unstable_bindgen::RpcPreconnectedClient(Some(Self::request_fd), param)
as *mut AIBinder;
new_spibinder(binder)
}
}
fn as_void_ptr(&mut self) -> *mut raw::c_void {
self as *mut _ as *mut raw::c_void
}
fn try_new_vsock_fd(&self) -> Result<i32> {
let vsock = self.vm.connectVsock(COMPOS_VSOCK_PORT as i32)?;
// Ownership of the fd is transferred to binder
Ok(vsock.into_raw_fd())
}
fn new_vsock_fd(&self) -> i32 {
self.try_new_vsock_fd().unwrap_or_else(|e| {
warn!("Connecting vsock failed: {}", e);
-1_i32
})
}
unsafe extern "C" fn request_fd(param: *mut raw::c_void) -> raw::c_int {
// SAFETY: This is only ever called by RpcPreconnectedClient, within the lifetime of the
// VsockFactory, with param taking the value returned by as_void_ptr (so a properly aligned
// non-null pointer to an initialized instance).
let vsock_factory = param as *mut Self;
vsock_factory.as_ref().unwrap().new_vsock_fd()
}
}
struct VmCallback();
impl Interface for VmCallback {}

View File

@ -9,9 +9,14 @@ rust_library {
edition: "2021",
rustlibs: [
"android.system.virtualizationservice-rust",
"libbinder_rpc_unstable_bindgen",
"libbinder_rs",
"liblog_rust",
"libthiserror",
],
shared_libs: [
"libbinder_rpc_unstable",
],
apex_available: [
"com.android.compos",
"com.android.virt",

View File

@ -13,6 +13,7 @@
// limitations under the License.
use super::DeathReason;
use android_system_virtualizationservice::binder::StatusCode;
use thiserror::Error;
/// An error while waiting for a VM to do something.
@ -31,3 +32,14 @@ pub enum VmWaitError {
#[error("VM payload finished.")]
Finished,
}
/// An error connection to a VM RPC Binder service.
#[derive(Clone, Debug, Error)]
pub enum GetServiceError {
/// The RPC binder connection failed.
#[error("Vsock connection to RPC binder failed.")]
ConnectionFailed,
/// The AIDL service type didn't match.
#[error("Service type didn't match ({0}).")]
WrongServiceType(StatusCode),
}

View File

@ -16,11 +16,12 @@
mod death_reason;
mod errors;
mod rpc_binder;
mod sync;
pub use crate::death_reason::DeathReason;
pub use crate::errors::VmWaitError;
use crate::sync::Monitor;
pub use crate::errors::{GetServiceError, VmWaitError};
use crate::{rpc_binder::VsockFactory, sync::Monitor};
use android_system_virtualizationservice::{
aidl::android::system::virtualizationservice::{
DeathReason::DeathReason as AidlDeathReason,
@ -31,7 +32,7 @@ use android_system_virtualizationservice::{
VirtualMachineState::VirtualMachineState,
},
binder::{
wait_for_interface, BinderFeatures, DeathRecipient, IBinder, Interface,
wait_for_interface, BinderFeatures, DeathRecipient, FromIBinder, IBinder, Interface,
ParcelFileDescriptor, Result as BinderResult, StatusCode, Strong,
},
};
@ -130,6 +131,18 @@ impl VmInstance {
Ok(())
}
}
/// Tries to connect to an RPC Binder service provided by the VM on the given vsock port.
pub fn get_service<T: FromIBinder + ?Sized>(
&self,
port: u32,
) -> Result<Strong<T>, GetServiceError> {
let mut vsock_factory = VsockFactory::new(&*self.vm, port);
let ibinder = vsock_factory.connect_rpc_client()?;
FromIBinder::try_from(ibinder).map_err(GetServiceError::WrongServiceType)
}
}
impl Debug for VmInstance {

View File

@ -0,0 +1,72 @@
// 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.
use crate::errors::GetServiceError;
use android_system_virtualizationservice::{
aidl::android::system::virtualizationservice::IVirtualMachine::IVirtualMachine,
};
use binder::unstable_api::{new_spibinder, AIBinder};
use log::warn;
use std::os::{raw, unix::io::IntoRawFd};
pub struct VsockFactory<'a> {
vm: &'a dyn IVirtualMachine,
port: u32,
}
impl<'a> VsockFactory<'a> {
pub fn new(vm: &'a dyn IVirtualMachine, port: u32) -> Self {
Self { vm, port }
}
pub fn connect_rpc_client(&mut self) -> Result<binder::SpIBinder, GetServiceError> {
let param = self.as_void_ptr();
unsafe {
// SAFETY: AIBinder returned by RpcPreconnectedClient has correct reference count, and
// the ownership can be safely taken by new_spibinder.
// RpcPreconnectedClient does not take ownership of param, only passing it to
// request_fd.
let binder =
binder_rpc_unstable_bindgen::RpcPreconnectedClient(Some(Self::request_fd), param)
as *mut AIBinder;
new_spibinder(binder).ok_or(GetServiceError::ConnectionFailed)
}
}
fn as_void_ptr(&mut self) -> *mut raw::c_void {
self as *mut _ as *mut raw::c_void
}
fn new_vsock_fd(&self) -> i32 {
match self.vm.connectVsock(self.port as i32) {
Ok(vsock) => {
// Ownership of the fd is transferred to binder
vsock.into_raw_fd()
}
Err(e) => {
warn!("Vsock connection failed: {}", e);
-1
}
}
}
unsafe extern "C" fn request_fd(param: *mut raw::c_void) -> raw::c_int {
// SAFETY: This is only ever called by RpcPreconnectedClient, within the lifetime of the
// VsockFactory, with param taking the value returned by as_void_ptr (so a properly aligned
// non-null pointer to an initialized instance).
let vsock_factory = param as *mut Self;
vsock_factory.as_ref().unwrap().new_vsock_fd()
}
}