blob: 3876d39e8c1c9ed08d2b61a7e7d5a3116ea8e99b [file] [log] [blame]
// 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.
//! Android Virtualization Manager
mod aidl;
mod atom;
mod composite;
mod crosvm;
mod debug_config;
mod dt_overlay;
mod payload;
mod selinux;
use crate::aidl::{GLOBAL_SERVICE, VirtualizationService};
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualizationService::BnVirtualizationService;
use anyhow::{bail, Result};
use binder::{BinderFeatures, ProcessState};
use log::{info, LevelFilter};
use rpcbinder::{FileDescriptorTransportMode, RpcServer};
use std::os::unix::io::{AsFd, RawFd};
use std::sync::LazyLock;
use clap::Parser;
use nix::unistd::{write, Pid, Uid};
use rustutils::inherited_fd::take_fd_ownership;
use std::os::unix::raw::{pid_t, uid_t};
const LOG_TAG: &str = "virtmgr";
static PID_CURRENT: LazyLock<Pid> = LazyLock::new(Pid::this);
static PID_PARENT: LazyLock<Pid> = LazyLock::new(Pid::parent);
static UID_CURRENT: LazyLock<Uid> = LazyLock::new(Uid::current);
fn get_this_pid() -> pid_t {
// Return the process ID of this process.
PID_CURRENT.as_raw()
}
fn get_calling_pid() -> pid_t {
// The caller is the parent of this process.
PID_PARENT.as_raw()
}
fn get_calling_uid() -> uid_t {
// The caller and this process share the same UID.
UID_CURRENT.as_raw()
}
#[derive(Parser)]
struct Args {
/// File descriptor inherited from the caller to run RpcBinder server on.
/// This should be one end of a socketpair() compatible with RpcBinder's
/// UDS bootstrap transport.
#[clap(long)]
rpc_server_fd: RawFd,
/// File descriptor inherited from the caller to signal RpcBinder server
/// readiness. This should be one end of pipe() and the caller should be
/// waiting for HUP on the other end.
#[clap(long)]
ready_fd: RawFd,
}
fn check_vm_support() -> Result<()> {
if hypervisor_props::is_any_vm_supported()? {
Ok(())
} else {
// This should never happen, it indicates a misconfigured device where the virt APEX
// is present but VMs are not supported. If it does happen, fail fast to avoid wasting
// resources trying.
bail!("Device doesn't support protected or non-protected VMs")
}
}
fn main() {
// SAFETY: This is very early in the process. Nobody has taken ownership of the inherited FDs
// yet.
unsafe { rustutils::inherited_fd::init_once() }
.expect("Failed to take ownership of inherited FDs");
android_logger::init_once(
android_logger::Config::default()
.with_tag(LOG_TAG)
.with_max_level(LevelFilter::Info)
.with_log_buffer(android_logger::LogId::System),
);
check_vm_support().unwrap();
let args = Args::parse();
let rpc_server_fd =
take_fd_ownership(args.rpc_server_fd).expect("Failed to take ownership of rpc_server_fd");
let ready_fd = take_fd_ownership(args.ready_fd).expect("Failed to take ownership of ready_fd");
// Start thread pool for kernel Binder connection to VirtualizationServiceInternal.
ProcessState::start_thread_pool();
if cfg!(early) {
// we can't access VirtualizationServiceInternal, so directly call rlimit
let pid = i32::from(*PID_CURRENT);
let lim = libc::rlimit { rlim_cur: libc::RLIM_INFINITY, rlim_max: libc::RLIM_INFINITY };
// SAFETY: borrowing the new limit struct only. prlimit doesn't use lim outside its lifetime
let ret = unsafe { libc::prlimit(pid, libc::RLIMIT_MEMLOCK, &lim, std::ptr::null_mut()) };
if ret == -1 {
panic!("rlimit error: {}", std::io::Error::last_os_error());
} else if ret != 0 {
panic!("Unexpected return value from prlimit(): {ret}");
}
} else {
GLOBAL_SERVICE.removeMemlockRlimit().expect("Failed to remove memlock rlimit");
}
let service = VirtualizationService::init();
let service =
BnVirtualizationService::new_binder(service, BinderFeatures::default()).as_binder();
let server = RpcServer::new_unix_domain_bootstrap(service, rpc_server_fd)
.expect("Failed to start RpcServer");
server.set_supported_file_descriptor_transport_modes(&[FileDescriptorTransportMode::Unix]);
info!("Started VirtualizationService RpcServer. Ready to accept connections");
// Signal readiness to the caller by closing our end of the pipe.
write(ready_fd.as_fd(), "o".as_bytes())
.expect("Failed to write a single character through ready_fd");
drop(ready_fd);
server.join();
info!("Shutting down VirtualizationService RpcServer");
}