diff --git a/compos/Android.bp b/compos/Android.bp index 9428210a..ad99d51e 100644 --- a/compos/Android.bp +++ b/compos/Android.bp @@ -28,7 +28,7 @@ rust_binary { rust_binary { name: "compsvc", - srcs: ["src/compsvc.rs"], + srcs: ["src/compsvc_main.rs"], rustlibs: [ "compos_aidl_interface-rust", "libandroid_logger", diff --git a/compos/src/compsvc.rs b/compos/src/compsvc.rs index 4ad2e030..3903cd0b 100644 --- a/compos/src/compsvc.rs +++ b/compos/src/compsvc.rs @@ -19,18 +19,14 @@ //! read/write. The service also attempts to sandbox the execution so that one task cannot leak or //! impact future tasks. //! -//! Example: -//! $ compsvc /system/bin/sleep -//! //! The current architecture / process hierarchy looks like: //! - compsvc (handle requests) //! - compsvc_worker (for environment setup) //! - authfs (fd translation) //! - actual task -use anyhow::{bail, Context, Result}; -use binder::unstable_api::AsNative; -use log::{debug, error}; +use anyhow::Result; +use log::error; use minijail::{self, Minijail}; use std::path::PathBuf; @@ -39,29 +35,29 @@ use compos_aidl_interface::aidl::com::android::compos::ICompService::{ }; use compos_aidl_interface::aidl::com::android::compos::Metadata::Metadata; use compos_aidl_interface::binder::{ - add_service, BinderFeatures, Interface, ProcessState, Result as BinderResult, Status, - StatusCode, Strong, + BinderFeatures, Interface, Result as BinderResult, Status, StatusCode, Strong, }; -mod common; -use common::{SERVICE_NAME, VSOCK_PORT}; - const WORKER_BIN: &str = "/apex/com.android.compos/bin/compsvc_worker"; + // TODO: Replace with a valid directory setup in the VM. const AUTHFS_MOUNTPOINT: &str = "/data/local/tmp"; +/// Constructs a binder object that implements ICompService. task_bin is the path to the binary that will +/// be run when execute() is called. If debuggable is true then stdout/stderr from the binary will be +/// available for debugging. +pub fn new_binder(task_bin: String, debuggable: bool) -> Strong { + let service = CompService { worker_bin: PathBuf::from(WORKER_BIN), task_bin, debuggable }; + BnCompService::new_binder(service, BinderFeatures::default()) +} + struct CompService { - worker_bin: PathBuf, task_bin: String, - rpc_binder: bool, + worker_bin: PathBuf, debuggable: bool, } impl CompService { - pub fn new_binder(service: CompService) -> Strong { - BnCompService::new_binder(service, BinderFeatures::default()) - } - fn run_worker_in_jail_and_wait(&self, args: &[String]) -> Result<(), minijail::Error> { let mut jail = Minijail::new()?; @@ -124,56 +120,3 @@ impl ICompService for CompService { } } } - -fn parse_args() -> Result { - #[rustfmt::skip] - let matches = clap::App::new("compsvc") - .arg(clap::Arg::with_name("debug") - .long("debug")) - .arg(clap::Arg::with_name("task_bin") - .required(true)) - .arg(clap::Arg::with_name("rpc_binder") - .long("rpc-binder")) - .get_matches(); - - Ok(CompService { - task_bin: matches.value_of("task_bin").unwrap().to_string(), - worker_bin: PathBuf::from(WORKER_BIN), - rpc_binder: matches.is_present("rpc_binder"), - debuggable: matches.is_present("debug"), - }) -} - -fn main() -> Result<()> { - android_logger::init_once( - android_logger::Config::default().with_tag("compsvc").with_min_level(log::Level::Debug), - ); - - let service = parse_args()?; - - if service.rpc_binder { - let mut service = CompService::new_binder(service).as_binder(); - debug!("compsvc is starting as a rpc service."); - // SAFETY: Service ownership is transferring to the server and won't be valid afterward. - // Plus the binder objects are threadsafe. - let retval = unsafe { - binder_rpc_unstable_bindgen::RunRpcServer( - service.as_native_mut() as *mut binder_rpc_unstable_bindgen::AIBinder, - VSOCK_PORT, - ) - }; - if retval { - debug!("RPC server has shut down gracefully"); - Ok(()) - } else { - bail!("Premature termination of RPC server"); - } - } else { - ProcessState::start_thread_pool(); - debug!("compsvc is starting as a local service."); - add_service(SERVICE_NAME, CompService::new_binder(service).as_binder()) - .with_context(|| format!("Failed to register service {}", SERVICE_NAME))?; - ProcessState::join_thread_pool(); - bail!("Unexpected exit after join_thread_pool") - } -} diff --git a/compos/src/compsvc_main.rs b/compos/src/compsvc_main.rs new file mode 100644 index 00000000..111a819a --- /dev/null +++ b/compos/src/compsvc_main.rs @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2021 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. + */ + +//! A tool to start a standalone compsvc server, either in the host using Binder or in a VM using +//! RPC binder over vsock. +//! +//! Example: +//! $ compsvc /system/bin/sleep + +mod common; +mod compsvc; + +use crate::common::{SERVICE_NAME, VSOCK_PORT}; +use anyhow::{bail, Context, Result}; +use binder::unstable_api::AsNative; +use compos_aidl_interface::binder::{add_service, ProcessState}; +use log::debug; + +struct Config { + task_bin: String, + rpc_binder: bool, + debuggable: bool, +} + +fn parse_args() -> Result { + #[rustfmt::skip] + let matches = clap::App::new("compsvc") + .arg(clap::Arg::with_name("debug") + .long("debug")) + .arg(clap::Arg::with_name("task_bin") + .required(true)) + .arg(clap::Arg::with_name("rpc_binder") + .long("rpc-binder")) + .get_matches(); + + Ok(Config { + task_bin: matches.value_of("task_bin").unwrap().to_string(), + rpc_binder: matches.is_present("rpc_binder"), + debuggable: matches.is_present("debug"), + }) +} + +fn main() -> Result<()> { + android_logger::init_once( + android_logger::Config::default().with_tag("compsvc").with_min_level(log::Level::Debug), + ); + + let config = parse_args()?; + let mut service = compsvc::new_binder(config.task_bin, config.debuggable).as_binder(); + if config.rpc_binder { + debug!("compsvc is starting as a rpc service."); + // SAFETY: Service ownership is transferring to the server and won't be valid afterward. + // Plus the binder objects are threadsafe. + let retval = unsafe { + binder_rpc_unstable_bindgen::RunRpcServer( + service.as_native_mut() as *mut binder_rpc_unstable_bindgen::AIBinder, + VSOCK_PORT, + ) + }; + if retval { + debug!("RPC server has shut down gracefully"); + Ok(()) + } else { + bail!("Premature termination of RPC server"); + } + } else { + ProcessState::start_thread_pool(); + debug!("compsvc is starting as a local service."); + add_service(SERVICE_NAME, service) + .with_context(|| format!("Failed to register service {}", SERVICE_NAME))?; + ProcessState::join_thread_pool(); + bail!("Unexpected exit after join_thread_pool") + } +}