[rpc_binder] Create RpcServer with new_bound_socket

This cl is part of the change to replace the init-dependent binder
API ARpcServer_newInitUnixDomain with a more generic version
ARpcServer_newBoundSocket.

Test: atest microdroid_manager_test
Test: m authfs_service
Bug: 275729094
Change-Id: I6e54166f919f0033bf5357cd0e1ece4e9d54f763
diff --git a/authfs/service/Android.bp b/authfs/service/Android.bp
index de6326d..2101a36 100644
--- a/authfs/service/Android.bp
+++ b/authfs/service/Android.bp
@@ -17,6 +17,7 @@
         "liblog_rust",
         "libnix",
         "librpcbinder_rs",
+        "librustutils",
         "libshared_child",
     ],
     prefer_rlib: true,
diff --git a/authfs/service/src/main.rs b/authfs/service/src/main.rs
index e710f07..78de07a 100644
--- a/authfs/service/src/main.rs
+++ b/authfs/service/src/main.rs
@@ -25,8 +25,10 @@
 use anyhow::{bail, Result};
 use log::*;
 use rpcbinder::RpcServer;
+use rustutils::sockets::android_get_control_socket;
 use std::ffi::OsString;
 use std::fs::{create_dir, read_dir, remove_dir_all, remove_file};
+use std::os::unix::io::{FromRawFd, OwnedFd};
 use std::sync::atomic::{AtomicUsize, Ordering};
 
 use authfs_aidl_interface::aidl::com::android::virt::fs::AuthFsConfig::AuthFsConfig;
@@ -106,6 +108,25 @@
     Ok(())
 }
 
+/// Prepares a socket file descriptor for the authfs service.
+///
+/// # Safety requirement
+///
+/// The caller must ensure that this function is the only place that claims ownership
+/// of the file descriptor and it is called only once.
+unsafe fn prepare_authfs_service_socket() -> Result<OwnedFd> {
+    let raw_fd = android_get_control_socket(AUTHFS_SERVICE_SOCKET_NAME)?;
+
+    // Creating OwnedFd for stdio FDs is not safe.
+    if [libc::STDIN_FILENO, libc::STDOUT_FILENO, libc::STDERR_FILENO].contains(&raw_fd) {
+        bail!("File descriptor {raw_fd} is standard I/O descriptor");
+    }
+    // SAFETY: Initializing OwnedFd for a RawFd created by the init.
+    // We checked that the integer value corresponds to a valid FD and that the caller
+    // ensures that this is the only place to claim its ownership.
+    Ok(unsafe { OwnedFd::from_raw_fd(raw_fd) })
+}
+
 fn try_main() -> Result<()> {
     let debuggable = env!("TARGET_BUILD_VARIANT") != "user";
     let log_level = if debuggable { log::Level::Trace } else { log::Level::Info };
@@ -115,9 +136,11 @@
 
     clean_up_working_directory()?;
 
+    // SAFETY: This is the only place we take the ownership of the fd of the authfs service.
+    let socket_fd = unsafe { prepare_authfs_service_socket()? };
     let service = AuthFsService::new_binder(debuggable).as_binder();
     debug!("{} is starting as a rpc service.", AUTHFS_SERVICE_SOCKET_NAME);
-    let server = RpcServer::new_init_unix_domain(service, AUTHFS_SERVICE_SOCKET_NAME)?;
+    let server = RpcServer::new_bound_socket(service, socket_fd)?;
     info!("The RPC server '{}' is running.", AUTHFS_SERVICE_SOCKET_NAME);
     server.join();
     info!("The RPC server at '{}' has shut down gracefully.", AUTHFS_SERVICE_SOCKET_NAME);
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index be86247..8fa2807 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -58,6 +58,7 @@
 use std::io::{Read, Write};
 use std::os::unix::process::CommandExt;
 use std::os::unix::process::ExitStatusExt;
+use std::os::unix::io::{FromRawFd, OwnedFd};
 use std::path::Path;
 use std::process::{Child, Command, Stdio};
 use std::str;
@@ -190,23 +191,36 @@
     })
 }
 
-fn prepare_vm_payload_service_socket() -> Result<()> {
-    android_get_control_socket(VM_PAYLOAD_SERVICE_SOCKET_NAME)?;
+/// Prepares a socket file descriptor for the vm payload service.
+///
+/// # Safety requirement
+///
+/// The caller must ensure that this function is the only place that claims ownership
+/// of the file descriptor and it is called only once.
+unsafe fn prepare_vm_payload_service_socket() -> Result<OwnedFd> {
+    let raw_fd = android_get_control_socket(VM_PAYLOAD_SERVICE_SOCKET_NAME)?;
 
-    // TODO(b/275729094): Convert the obtained file descriptor to `OwnedFd`
-    //  and use it to set the `RpcServer`.
-    Ok(())
+    // Creating OwnedFd for stdio FDs is not safe.
+    if [libc::STDIN_FILENO, libc::STDOUT_FILENO, libc::STDERR_FILENO].contains(&raw_fd) {
+        bail!("File descriptor {raw_fd} is standard I/O descriptor");
+    }
+    // SAFETY: Initializing OwnedFd for a RawFd created by the init.
+    // We checked that the integer value corresponds to a valid FD and that the caller
+    // ensures that this is the only place to claim its ownership.
+    Ok(unsafe { OwnedFd::from_raw_fd(raw_fd) })
 }
 
 fn try_main() -> Result<()> {
     let _ignored = kernlog::init();
     info!("started.");
 
+    // SAFETY: This is the only place we take the ownership of the fd of the vm payload service.
+    //
     // To ensure that the CLOEXEC flag is set on the file descriptor as early as possible,
     // it is necessary to fetch the socket corresponding to vm_payload_service at the
     // very beginning, as android_get_control_socket() sets the CLOEXEC flag on the file
     // descriptor.
-    prepare_vm_payload_service_socket()?;
+    let vm_payload_service_fd = unsafe { prepare_vm_payload_service_socket()? };
 
     load_crashkernel_if_supported().context("Failed to load crashkernel")?;
 
@@ -217,7 +231,7 @@
         .context("cannot connect to VirtualMachineService")
         .map_err(|e| MicrodroidError::FailedToConnectToVirtualizationService(e.to_string()))?;
 
-    match try_run_payload(&service) {
+    match try_run_payload(&service, vm_payload_service_fd) {
         Ok(code) => {
             if code == 0 {
                 info!("task successfully finished");
@@ -331,7 +345,10 @@
     Ok(Some(u32::from_be_bytes(log) == 1))
 }
 
-fn try_run_payload(service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
+fn try_run_payload(
+    service: &Strong<dyn IVirtualMachineService>,
+    vm_payload_service_fd: OwnedFd,
+) -> Result<i32> {
     let metadata = load_metadata().context("Failed to load payload metadata")?;
     let dice = DiceDriver::new(Path::new("/dev/open-dice0")).context("Failed to load DICE")?;
 
@@ -448,7 +465,12 @@
     // Wait until zipfuse has mounted the APKs so we can access the payload
     zipfuse.wait_until_done()?;
 
-    register_vm_payload_service(allow_restricted_apis, service.clone(), dice_artifacts)?;
+    register_vm_payload_service(
+        allow_restricted_apis,
+        service.clone(),
+        dice_artifacts,
+        vm_payload_service_fd,
+    )?;
 
     // Wait for encryptedstore to finish mounting the storage (if enabled) before setting
     // microdroid_manager.init_done. Reason is init stops uneventd after that.
diff --git a/microdroid_manager/src/vm_payload_service.rs b/microdroid_manager/src/vm_payload_service.rs
index 11e6967..bcddc3a 100644
--- a/microdroid_manager/src/vm_payload_service.rs
+++ b/microdroid_manager/src/vm_payload_service.rs
@@ -23,6 +23,7 @@
 use diced_open_dice::{DiceArtifacts, OwnedDiceArtifacts};
 use log::{error, info};
 use rpcbinder::RpcServer;
+use std::os::unix::io::OwnedFd;
 
 /// Implementation of `IVmPayloadService`.
 struct VmPayloadService {
@@ -101,16 +102,14 @@
     allow_restricted_apis: bool,
     vm_service: Strong<dyn IVirtualMachineService>,
     dice: OwnedDiceArtifacts,
+    vm_payload_service_fd: OwnedFd,
 ) -> Result<()> {
     let vm_payload_binder = BnVmPayloadService::new_binder(
         VmPayloadService::new(allow_restricted_apis, vm_service, dice),
         BinderFeatures::default(),
     );
 
-    let server = RpcServer::new_init_unix_domain(
-        vm_payload_binder.as_binder(),
-        VM_PAYLOAD_SERVICE_SOCKET_NAME,
-    )?;
+    let server = RpcServer::new_bound_socket(vm_payload_binder.as_binder(), vm_payload_service_fd)?;
     info!("The RPC server '{}' is running.", VM_PAYLOAD_SERVICE_SOCKET_NAME);
 
     // Move server reference into a background thread and run it forever.