Move VsockFactory into VM client library.
Test: ComposHostTestCases compos_key_tests
Change-Id: I0500c9ad46df4c004f033161ade53b94d3d2afea
diff --git a/compos/common/Android.bp b/compos/common/Android.bp
index 0377474..51f97f8 100644
--- a/compos/common/Android.bp
+++ b/compos/common/Android.bp
@@ -13,7 +13,6 @@
"libanyhow",
"libbinder_common",
"libbinder_rpc_unstable_bindgen",
- "libbinder_rs",
"liblog_rust",
"libnum_traits",
"librustutils",
diff --git a/compos/common/binder.rs b/compos/common/binder.rs
index 4935b80..45139f3 100644
--- a/compos/common/binder.rs
+++ b/compos/common/binder.rs
@@ -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;
diff --git a/compos/common/compos_client.rs b/compos/common/compos_client.rs
index 15f74cd..b55f3ab 100644
--- a/compos/common/compos_client.rs
+++ b/compos/common/compos_client.rs
@@ -20,7 +20,6 @@
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::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 @@
/// 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 @@
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 {}
diff --git a/vmclient/Android.bp b/vmclient/Android.bp
index 3310ec6..8ad5adf 100644
--- a/vmclient/Android.bp
+++ b/vmclient/Android.bp
@@ -9,9 +9,14 @@
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",
diff --git a/vmclient/src/errors.rs b/vmclient/src/errors.rs
index b9de868..532706d 100644
--- a/vmclient/src/errors.rs
+++ b/vmclient/src/errors.rs
@@ -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 @@
#[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),
+}
diff --git a/vmclient/src/lib.rs b/vmclient/src/lib.rs
index 888092f..d182b60 100644
--- a/vmclient/src/lib.rs
+++ b/vmclient/src/lib.rs
@@ -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 @@
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 @@
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 {
diff --git a/vmclient/src/rpc_binder.rs b/vmclient/src/rpc_binder.rs
new file mode 100644
index 0000000..fee643f
--- /dev/null
+++ b/vmclient/src/rpc_binder.rs
@@ -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()
+ }
+}