Merge "virtualizationservice: "prefer_staged" for apexes"
diff --git a/authfs/fd_server/src/main.rs b/authfs/fd_server/src/main.rs
index 12f013c..32ffc0a 100644
--- a/authfs/fd_server/src/main.rs
+++ b/authfs/fd_server/src/main.rs
@@ -32,6 +32,7 @@
use std::convert::TryInto;
use std::fs::File;
use std::io;
+use std::os::raw;
use std::os::unix::fs::FileExt;
use std::os::unix::io::{AsRawFd, FromRawFd};
@@ -292,7 +293,12 @@
Ok((fd, FdConfig::ReadWrite(file)))
}
-fn parse_args() -> Result<BTreeMap<i32, FdConfig>> {
+struct Args {
+ fd_pool: BTreeMap<i32, FdConfig>,
+ ready_fd: Option<File>,
+}
+
+fn parse_args() -> Result<Args> {
#[rustfmt::skip]
let matches = clap::App::new("fd_server")
.arg(clap::Arg::with_name("ro-fds")
@@ -303,6 +309,9 @@
.long("rw-fds")
.multiple(true)
.number_of_values(1))
+ .arg(clap::Arg::with_name("ready-fd")
+ .long("ready-fd")
+ .takes_value(true))
.get_matches();
let mut fd_pool = BTreeMap::new();
@@ -318,8 +327,13 @@
fd_pool.insert(fd, config);
}
}
-
- Ok(fd_pool)
+ let ready_fd = if let Some(arg) = matches.value_of("ready-fd") {
+ let fd = arg.parse::<i32>()?;
+ Some(fd_to_file(fd)?)
+ } else {
+ None
+ };
+ Ok(Args { fd_pool, ready_fd })
}
fn main() -> Result<()> {
@@ -327,16 +341,22 @@
android_logger::Config::default().with_tag("fd_server").with_min_level(log::Level::Debug),
);
- let fd_pool = parse_args()?;
+ let args = parse_args()?;
- let mut service = FdService::new_binder(fd_pool).as_binder();
+ let mut service = FdService::new_binder(args.fd_pool).as_binder();
+ let mut ready_notifier = ReadyNotifier(args.ready_fd);
+
debug!("fd_server 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.
+ // RunRpcServerCallback does not retain a reference to ready_callback, and only ever
+ // calls it with the param we provide during the lifetime of ready_notifier.
let retval = unsafe {
- binder_rpc_unstable_bindgen::RunRpcServer(
+ binder_rpc_unstable_bindgen::RunRpcServerCallback(
service.as_native_mut() as *mut binder_rpc_unstable_bindgen::AIBinder,
RPC_SERVICE_PORT,
+ Some(ReadyNotifier::ready_callback),
+ ready_notifier.as_void_ptr(),
)
};
if retval {
@@ -346,3 +366,25 @@
bail!("Premature termination of RPC server");
}
}
+
+struct ReadyNotifier(Option<File>);
+
+impl ReadyNotifier {
+ fn notify(&mut self) {
+ debug!("fd_server is ready");
+ // Close the ready-fd if we were given one to signal our readiness.
+ drop(self.0.take());
+ }
+
+ fn as_void_ptr(&mut self) -> *mut raw::c_void {
+ self as *mut _ as *mut raw::c_void
+ }
+
+ unsafe extern "C" fn ready_callback(param: *mut raw::c_void) {
+ // SAFETY: This is only ever called by RunRpcServerCallback, within the lifetime of the
+ // ReadyNotifier, with param taking the value returned by as_void_ptr (so a properly aligned
+ // non-null pointer to an initialized instance).
+ let ready_notifier = param as *mut Self;
+ ready_notifier.as_mut().unwrap().notify()
+ }
+}
diff --git a/authfs/service/src/authfs.rs b/authfs/service/src/authfs.rs
index 5601738..6d87243 100644
--- a/authfs/service/src/authfs.rs
+++ b/authfs/service/src/authfs.rs
@@ -82,8 +82,11 @@
&config.outputFdAnnotations,
debuggable,
)?;
- wait_until_authfs_ready(&mountpoint).map_err(|e| {
- debug!("Wait for authfs: {:?}", child.wait());
+ wait_until_authfs_ready(&child, &mountpoint).map_err(|e| {
+ match child.wait() {
+ Ok(status) => debug!("Wait for authfs: {}", status),
+ Err(e) => warn!("Failed to wait for child: {}", e),
+ }
e
})?;
@@ -144,13 +147,18 @@
SharedChild::spawn(&mut command).context("Spawn authfs")
}
-fn wait_until_authfs_ready(mountpoint: &OsStr) -> Result<()> {
+fn wait_until_authfs_ready(child: &SharedChild, mountpoint: &OsStr) -> Result<()> {
let start_time = Instant::now();
loop {
if is_fuse(mountpoint)? {
break;
}
+ if let Some(exit_status) = child.try_wait()? {
+ // If the child has exited, we will never become ready.
+ bail!("Child has exited: {}", exit_status);
+ }
if start_time.elapsed() > AUTHFS_SETUP_TIMEOUT_SEC {
+ let _ = child.kill();
bail!("Time out mounting authfs");
}
sleep(AUTHFS_SETUP_POLL_INTERVAL_MS);
diff --git a/authfs/service/src/main.rs b/authfs/service/src/main.rs
index af8c7f9..890e108 100644
--- a/authfs/service/src/main.rs
+++ b/authfs/service/src/main.rs
@@ -59,7 +59,7 @@
create_dir(&mountpoint).map_err(|e| {
new_binder_exception(
ExceptionCode::SERVICE_SPECIFIC,
- format!("Cannot create mount directory {:?}: {}", &mountpoint, e),
+ format!("Cannot create mount directory {:?}: {:?}", &mountpoint, e),
)
})?;
@@ -109,7 +109,7 @@
Ok(())
}
-fn main() -> Result<()> {
+fn try_main() -> Result<()> {
let debuggable = env!("TARGET_BUILD_VARIANT") != "user";
let log_level = if debuggable { log::Level::Trace } else { log::Level::Info };
android_logger::init_once(
@@ -128,3 +128,10 @@
ProcessState::join_thread_pool();
bail!("Unexpected exit after join_thread_pool")
}
+
+fn main() {
+ if let Err(e) = try_main() {
+ error!("failed with {:?}", e);
+ std::process::exit(1);
+ }
+}
diff --git a/authfs/src/main.rs b/authfs/src/main.rs
index c85d801..ecb0e68 100644
--- a/authfs/src/main.rs
+++ b/authfs/src/main.rs
@@ -28,6 +28,7 @@
//! e.g. /mountpoint/42.
use anyhow::{bail, Context, Result};
+use log::error;
use std::collections::BTreeMap;
use std::convert::TryInto;
use std::fs::File;
@@ -325,7 +326,7 @@
Ok(file_pool)
}
-fn main() -> Result<()> {
+fn try_main() -> Result<()> {
let args = Args::from_args();
let log_level = if args.debug { log::Level::Debug } else { log::Level::Info };
@@ -337,3 +338,10 @@
fusefs::loop_forever(file_pool, &args.mount_point, &args.extra_options)?;
bail!("Unexpected exit after the handler loop")
}
+
+fn main() {
+ if let Err(e) = try_main() {
+ error!("failed with {:?}", e);
+ std::process::exit(1);
+ }
+}
diff --git a/binder_common/Android.bp b/binder_common/Android.bp
index 789a891..9e6d590 100644
--- a/binder_common/Android.bp
+++ b/binder_common/Android.bp
@@ -9,6 +9,7 @@
edition: "2018",
rustlibs: [
"libbinder_rs",
+ "liblazy_static",
],
apex_available: [
"com.android.compos",
diff --git a/binder_common/lazy_service.rs b/binder_common/lazy_service.rs
new file mode 100644
index 0000000..a2b85db
--- /dev/null
+++ b/binder_common/lazy_service.rs
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+//! Rust API for lazy (aka dynamic) AIDL services.
+//! See https://source.android.com/devices/architecture/aidl/dynamic-aidl.
+
+use binder::public_api::force_lazy_services_persist;
+use lazy_static::lazy_static;
+use std::sync::Mutex;
+
+// TODO(b/200924402): Move this class to libbinder_rs once the infrastructure needed exists.
+
+/// An RAII object to ensure a server of lazy services is not killed. During the lifetime of any of
+/// these objects the service manager will not not kill the current process even if none of its
+/// lazy services are in use.
+#[must_use]
+#[derive(Debug)]
+pub struct LazyServiceGuard {
+ // Prevent construction outside this module.
+ _private: (),
+}
+
+lazy_static! {
+ // Count of how many LazyServiceGuard objects are in existence.
+ static ref GUARD_COUNT: Mutex<u64> = Mutex::new(0);
+}
+
+impl LazyServiceGuard {
+ /// Create a new LazyServiceGuard to prevent the service manager prematurely killing this
+ /// process.
+ pub fn new() -> Self {
+ let mut count = GUARD_COUNT.lock().unwrap();
+ *count += 1;
+ if *count == 1 {
+ // It's important that we make this call with the mutex held, to make sure
+ // that multiple calls (e.g. if the count goes 1 -> 0 -> 1) are correctly
+ // sequenced. (That also means we can't just use an AtomicU64.)
+ force_lazy_services_persist(true);
+ }
+ Self { _private: () }
+ }
+}
+
+impl Drop for LazyServiceGuard {
+ fn drop(&mut self) {
+ let mut count = GUARD_COUNT.lock().unwrap();
+ *count -= 1;
+ if *count == 0 {
+ force_lazy_services_persist(false);
+ }
+ }
+}
+
+impl Clone for LazyServiceGuard {
+ fn clone(&self) -> Self {
+ Self::new()
+ }
+}
+
+impl Default for LazyServiceGuard {
+ fn default() -> Self {
+ Self::new()
+ }
+}
diff --git a/binder_common/lib.rs b/binder_common/lib.rs
index 54cb80e..055688a 100644
--- a/binder_common/lib.rs
+++ b/binder_common/lib.rs
@@ -16,6 +16,8 @@
//! Common items useful for binder clients and/or servers.
+pub mod lazy_service;
+
use binder::public_api::{ExceptionCode, Status};
use std::ffi::CString;
diff --git a/compos/aidl/com/android/compos/ICompOsService.aidl b/compos/aidl/com/android/compos/ICompOsService.aidl
index 7904130..29c453b 100644
--- a/compos/aidl/com/android/compos/ICompOsService.aidl
+++ b/compos/aidl/com/android/compos/ICompOsService.aidl
@@ -43,7 +43,22 @@
* @param fd_annotation Additional file descriptor information of the execution
* @return a CompilationResult
*/
- CompilationResult compile(in String[] args, in FdAnnotation fd_annotation);
+ CompilationResult compile_cmd(in String[] args, in FdAnnotation fd_annotation);
+
+ /**
+ * Runs dexopt compilation encoded in the marshaled dexopt arguments.
+ *
+ * To keep ART indepdendantly updatable, the compilation arguments are not stabilized. As a
+ * result, the arguments are marshaled into byte array. Upon received, the service asks ART to
+ * return relevant information (since ART is able to unmarshal its own encoding), in order to
+ * set up the execution context (mainly file descriptors for compiler input and output) then
+ * invokes the compiler.
+ *
+ * @param marshaledArguments The marshaled dexopt arguments.
+ * @param fd_annotation Additional file descriptor information of the execution.
+ * @return exit code
+ */
+ byte compile(in byte[] marshaledArguments, in FdAnnotation fd_annotation);
/**
* Generate a new public/private key pair suitable for signing CompOs output files.
diff --git a/compos/common/compos_client.rs b/compos/common/compos_client.rs
index e68deb8..a69538e 100644
--- a/compos/common/compos_client.rs
+++ b/compos/common/compos_client.rs
@@ -46,11 +46,8 @@
/// This owns an instance of the CompOS VM.
pub struct VmInstance {
- #[allow(dead_code)] // Prevent service manager from killing the dynamic service
- service: Strong<dyn IVirtualizationService>,
#[allow(dead_code)] // Keeps the VM alive even if we don`t touch it
vm: Strong<dyn IVirtualMachine>,
- #[allow(dead_code)] // TODO: Do we need this?
cid: i32,
}
@@ -63,9 +60,7 @@
}
/// Start a new CompOS VM instance using the specified instance image file.
- pub fn start(instance_image: &Path) -> Result<VmInstance> {
- let instance_image =
- File::open(instance_image).context("Failed to open instance image file")?;
+ pub fn start(instance_image: File) -> Result<VmInstance> {
let instance_fd = ParcelFileDescriptor::new(instance_image);
let apex_dir = Path::new(COMPOS_APEX_ROOT);
@@ -113,7 +108,7 @@
let cid = vm_state.wait_until_ready()?;
- Ok(VmInstance { service, vm, cid })
+ Ok(VmInstance { vm, cid })
}
/// Create and return an RPC Binder connection to the Comp OS service in the VM.
@@ -129,6 +124,7 @@
/// Return the CID of the VM.
pub fn cid(&self) -> i32 {
+ // TODO: Do we actually need/use this?
self.cid
}
}
@@ -227,9 +223,12 @@
}
fn wait_until_ready(&self) -> Result<i32> {
+ // 10s is long enough on real hardware, but it can take 90s when using nested
+ // virtualization.
+ // TODO(b/200924405): Reduce timeout/detect nested virtualization
let (state, result) = self
.state_ready
- .wait_timeout_while(self.mutex.lock().unwrap(), Duration::from_secs(20), |state| {
+ .wait_timeout_while(self.mutex.lock().unwrap(), Duration::from_secs(120), |state| {
state.cid.is_none() && !state.has_died
})
.unwrap();
diff --git a/compos/compos_key_cmd/compos_key_cmd.cpp b/compos/compos_key_cmd/compos_key_cmd.cpp
index e168648..f495816 100644
--- a/compos/compos_key_cmd/compos_key_cmd.cpp
+++ b/compos/compos_key_cmd/compos_key_cmd.cpp
@@ -156,7 +156,10 @@
bool waitUntilReady() {
std::unique_lock lock(mMutex);
- return mCv.wait_for(lock, std::chrono::seconds(20), [this] { return mReady || mDied; }) &&
+ // 10s is long enough on real hardware, but it can take 90s when using nested
+ // virtualization.
+ // TODO(b/200924405): Reduce timeout/detect nested virtualization
+ return mCv.wait_for(lock, std::chrono::seconds(120), [this] { return mReady || mDied; }) &&
!mDied;
}
diff --git a/compos/composd/aidl/android/system/composd/IIsolatedCompilationService.aidl b/compos/composd/aidl/android/system/composd/IIsolatedCompilationService.aidl
index 5ff72fe..a1bb92c 100644
--- a/compos/composd/aidl/android/system/composd/IIsolatedCompilationService.aidl
+++ b/compos/composd/aidl/android/system/composd/IIsolatedCompilationService.aidl
@@ -24,10 +24,19 @@
/**
* Run dex2oat in the currently running instance of the CompOS VM. This is a simple proxy
- * to ICompOsService#compile.
+ * to ICompOsService#compile_cmd.
*
* This method can only be called from odrefresh. If there is no currently running instance
* an error is returned.
*/
- CompilationResult compile(in String[] args, in FdAnnotation fd_annotation);
+ CompilationResult compile_cmd(in String[] args, in FdAnnotation fd_annotation);
+
+ /**
+ * Run dex2oat in the currently running instance of the CompOS VM. This is a simple proxy
+ * to ICompOsService#compile.
+ *
+ * This method can only be called from libcompos_client. If there is no currently running
+ * instance an error is returned.
+ */
+ byte compile(in byte[] marshaledArguments, in FdAnnotation fd_annotation);
}
diff --git a/compos/composd/src/instance_starter.rs b/compos/composd/src/instance_starter.rs
index ec95ff8..1751d35 100644
--- a/compos/composd/src/instance_starter.rs
+++ b/compos/composd/src/instance_starter.rs
@@ -89,8 +89,8 @@
let key_blob = fs::read(&self.key_blob).context("Reading private key blob")?;
let public_key = fs::read(&self.public_key).context("Reading public key")?;
- let vm_instance = VmInstance::start(&self.instance_image).context("Starting VM")?;
- let service = vm_instance.get_service().context("Connecting to CompOS")?;
+ let compos_instance = self.start_vm()?;
+ let service = &compos_instance.service;
if !service.verifySigningKey(&key_blob, &public_key).context("Verifying key pair")? {
bail!("Key pair invalid");
@@ -102,7 +102,7 @@
service.initializeSigningKey(&key_blob).context("Loading signing key")?;
- Ok(CompOsInstance { vm_instance, service })
+ Ok(compos_instance)
}
fn start_new_instance(
@@ -116,8 +116,8 @@
self.create_instance_image(virtualization_service)?;
- let vm_instance = VmInstance::start(&self.instance_image).context("Starting VM")?;
- let service = vm_instance.get_service().context("Connecting to CompOS")?;
+ let compos_instance = self.start_vm()?;
+ let service = &compos_instance.service;
let key_data = service.generateSigningKey().context("Generating signing key")?;
fs::write(&self.key_blob, &key_data.keyBlob).context("Writing key blob")?;
@@ -133,6 +133,17 @@
service.initializeSigningKey(&key_data.keyBlob).context("Loading signing key")?;
+ Ok(compos_instance)
+ }
+
+ fn start_vm(&self) -> Result<CompOsInstance> {
+ let instance_image = fs::OpenOptions::new()
+ .read(true)
+ .write(true)
+ .open(&self.instance_image)
+ .context("Failed to open instance image")?;
+ let vm_instance = VmInstance::start(instance_image).context("Starting VM")?;
+ let service = vm_instance.get_service().context("Connecting to CompOS")?;
Ok(CompOsInstance { vm_instance, service })
}
diff --git a/compos/composd/src/service.rs b/compos/composd/src/service.rs
index 2a67a27..be9c30c 100644
--- a/compos/composd/src/service.rs
+++ b/compos/composd/src/service.rs
@@ -47,7 +47,7 @@
to_binder_result(self.do_run_forced_compile())
}
- fn compile(
+ fn compile_cmd(
&self,
args: &[String],
fd_annotation: &FdAnnotation,
@@ -55,6 +55,10 @@
// TODO - check caller is odrefresh
to_binder_result(self.do_compile(args, fd_annotation))
}
+
+ fn compile(&self, _marshaled: &[u8], _fd_annotation: &FdAnnotation) -> binder::Result<i8> {
+ Err(new_binder_service_specific_error(-1, "Not yet implemented"))
+ }
}
fn to_binder_result<T>(result: Result<T>) -> binder::Result<T> {
@@ -89,6 +93,6 @@
fd_annotation: &FdAnnotation,
) -> Result<CompilationResult> {
let compos = self.instance_manager.get_running_service()?;
- compos.compile(args, fd_annotation).context("Compiling")
+ compos.compile_cmd(args, fd_annotation).context("Compiling")
}
}
diff --git a/compos/src/compilation.rs b/compos/src/compilation.rs
index fec82a6..1499d4b 100644
--- a/compos/src/compilation.rs
+++ b/compos/src/compilation.rs
@@ -52,7 +52,7 @@
/// Runs the compiler with given flags with file descriptors described in `fd_annotation` retrieved
/// via `authfs_service`. Returns exit code of the compiler process.
-pub fn compile(
+pub fn compile_cmd(
compiler_path: &Path,
compiler_args: &[String],
authfs_service: Strong<dyn IAuthFsService>,
diff --git a/compos/src/compsvc.rs b/compos/src/compsvc.rs
index 954adf5..08f3521 100644
--- a/compos/src/compsvc.rs
+++ b/compos/src/compsvc.rs
@@ -25,7 +25,7 @@
use std::path::PathBuf;
use std::sync::{Arc, RwLock};
-use crate::compilation::{compile, CompilerOutput};
+use crate::compilation::{compile_cmd, CompilerOutput};
use crate::compos_key_service::CompOsKeyService;
use crate::fsverity;
use authfs_aidl_interface::aidl::com::android::virt::fs::IAuthFsService::IAuthFsService;
@@ -85,14 +85,14 @@
}
}
- fn compile(
+ fn compile_cmd(
&self,
args: &[String],
fd_annotation: &FdAnnotation,
) -> BinderResult<CompilationResult> {
let authfs_service = get_authfs_service()?;
let output =
- compile(&self.dex2oat_path, args, authfs_service, fd_annotation).map_err(|e| {
+ compile_cmd(&self.dex2oat_path, args, authfs_service, fd_annotation).map_err(|e| {
new_binder_exception(
ExceptionCode::SERVICE_SPECIFIC,
format!("Compilation failed: {}", e),
@@ -124,6 +124,10 @@
}
}
+ fn compile(&self, _marshaled: &[u8], _fd_annotation: &FdAnnotation) -> BinderResult<i8> {
+ Err(new_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION, "Not yet implemented"))
+ }
+
fn generateSigningKey(&self) -> BinderResult<CompOsKeyData> {
self.key_service
.do_generate()
diff --git a/compos/src/compsvc_main.rs b/compos/src/compsvc_main.rs
index 388e79b..d0c920a 100644
--- a/compos/src/compsvc_main.rs
+++ b/compos/src/compsvc_main.rs
@@ -43,7 +43,14 @@
/// The CID representing the host VM
const VMADDR_CID_HOST: u32 = 2;
-fn main() -> Result<()> {
+fn main() {
+ if let Err(e) = try_main() {
+ error!("failed with {:?}", e);
+ std::process::exit(1);
+ }
+}
+
+fn try_main() -> Result<()> {
let args = clap::App::new("compsvc")
.arg(clap::Arg::with_name("log_to_stderr").long("log_to_stderr"))
.get_matches();
diff --git a/compos/src/pvm_exec.rs b/compos/src/pvm_exec.rs
index fdd9c57..fd5ffaf 100644
--- a/compos/src/pvm_exec.rs
+++ b/compos/src/pvm_exec.rs
@@ -32,8 +32,11 @@
use clap::{value_t, App, Arg};
use log::{debug, error, warn};
use minijail::Minijail;
-use nix::fcntl::{fcntl, FcntlArg::F_GETFD};
-use std::os::unix::io::RawFd;
+use nix::fcntl::{fcntl, FcntlArg::F_GETFD, OFlag};
+use nix::unistd::pipe2;
+use std::fs::File;
+use std::io::Read;
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::path::Path;
use std::process::exit;
@@ -69,7 +72,11 @@
}
}
-fn spawn_fd_server(fd_annotation: &FdAnnotation, debuggable: bool) -> Result<Minijail> {
+fn spawn_fd_server(
+ fd_annotation: &FdAnnotation,
+ ready_file: File,
+ debuggable: bool,
+) -> Result<Minijail> {
let mut inheritable_fds = if debuggable {
vec![1, 2] // inherit/redirect stdout/stderr for debugging
} else {
@@ -87,6 +94,10 @@
args.push(fd.to_string());
inheritable_fds.push(*fd);
}
+ let ready_fd = ready_file.as_raw_fd();
+ args.push("--ready-fd".to_string());
+ args.push(ready_fd.to_string());
+ inheritable_fds.push(ready_fd);
let jail = Minijail::new()?;
let _pid = jail.run(Path::new(FD_SERVER_BIN), &inheritable_fds, &args)?;
@@ -153,12 +164,31 @@
Ok(Config { args, fd_annotation: FdAnnotation { input_fds, output_fds }, cid, debuggable })
}
+fn create_pipe() -> Result<(File, File)> {
+ let (raw_read, raw_write) = pipe2(OFlag::O_CLOEXEC)?;
+ // SAFETY: We are the sole owners of these fds as they were just created.
+ let read_fd = unsafe { File::from_raw_fd(raw_read) };
+ let write_fd = unsafe { File::from_raw_fd(raw_write) };
+ Ok((read_fd, write_fd))
+}
+
+fn wait_for_fd_server_ready(mut ready_fd: File) -> Result<()> {
+ let mut buffer = [0];
+ // When fd_server is ready it closes its end of the pipe. And if it exits, the pipe is also
+ // closed. Either way this read will return 0 bytes at that point, and there's no point waiting
+ // any longer.
+ let _ = ready_fd.read(&mut buffer).context("Waiting for fd_server to be ready")?;
+ debug!("fd_server is ready");
+ Ok(())
+}
+
fn try_main() -> Result<()> {
// 1. Parse the command line arguments for collect execution data.
let Config { args, fd_annotation, cid, debuggable } = parse_args()?;
// 2. Spawn and configure a fd_server to serve remote read/write requests.
- let fd_server_jail = spawn_fd_server(&fd_annotation, debuggable)?;
+ let (ready_read_fd, ready_write_fd) = create_pipe()?;
+ let fd_server_jail = spawn_fd_server(&fd_annotation, ready_write_fd, debuggable)?;
let fd_server_lifetime = scopeguard::guard(fd_server_jail, |fd_server_jail| {
if let Err(e) = fd_server_jail.kill() {
if !matches!(e, minijail::Error::Killed(_)) {
@@ -171,11 +201,13 @@
let result = if cid == VMADDR_CID_ANY {
// Sentinel value that indicates we should use composd
let composd = get_composd()?;
- composd.compile(&args, &fd_annotation)
+ wait_for_fd_server_ready(ready_read_fd)?;
+ composd.compile_cmd(&args, &fd_annotation)
} else {
// Call directly into the VM
let compos_vm = get_rpc_binder(cid)?;
- compos_vm.compile(&args, &fd_annotation)
+ wait_for_fd_server_ready(ready_read_fd)?;
+ compos_vm.compile_cmd(&args, &fd_annotation)
};
let result = result.context("Binder call failed")?;
@@ -190,7 +222,7 @@
// Be explicit about the lifetime, which should last at least until the task is finished.
drop(fd_server_lifetime);
- if result.exitCode > 0 {
+ if result.exitCode != 0 {
error!("remote execution failed with exit code {}", result.exitCode);
exit(result.exitCode as i32);
}
diff --git a/compos/verify_key/verify_key.rs b/compos/verify_key/verify_key.rs
index 8439b97..0cc6473 100644
--- a/compos/verify_key/verify_key.rs
+++ b/compos/verify_key/verify_key.rs
@@ -87,8 +87,9 @@
let blob = read_small_file(blob).context("Failed to read key blob")?;
let public_key = read_small_file(public_key).context("Failed to read public key")?;
+ let instance_image = File::open(instance_image).context("Failed to open instance image")?;
- let vm_instance = VmInstance::start(&instance_image)?;
+ let vm_instance = VmInstance::start(instance_image)?;
let service = vm_instance.get_service()?;
let result = service.verifySigningKey(&blob, &public_key).context("Verifying signing key")?;
diff --git a/pvmfw/pvmfw.img b/pvmfw/pvmfw.img
new file mode 100644
index 0000000..317821f
--- /dev/null
+++ b/pvmfw/pvmfw.img
Binary files differ
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index b3d54ef..dbcc5ce 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -19,13 +19,11 @@
use crate::payload::add_microdroid_images;
use crate::{Cid, FIRST_GUEST_CID, SYSPROP_LAST_CID};
-use binder_common::new_binder_exception;
+use ::binder::unstable_api::AsNative;
use android_os_permissions_aidl::aidl::android::os::IPermissionController;
-use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualMachine::{
- BnVirtualMachine, IVirtualMachine,
-};
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
DiskImage::DiskImage,
+ IVirtualMachine::{BnVirtualMachine, IVirtualMachine},
IVirtualMachineCallback::IVirtualMachineCallback,
IVirtualizationService::IVirtualizationService,
PartitionType::PartitionType,
@@ -36,20 +34,24 @@
VirtualMachineState::VirtualMachineState,
};
use android_system_virtualizationservice::binder::{
- self, force_lazy_services_persist, BinderFeatures, ExceptionCode, Interface, ParcelFileDescriptor, Status, Strong, ThreadState,
+ self, BinderFeatures, ExceptionCode, Interface, ParcelFileDescriptor, Status, Strong,
+ ThreadState,
};
-use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::{
- VM_BINDER_SERVICE_PORT, VM_STREAM_SERVICE_PORT, BnVirtualMachineService, IVirtualMachineService,
+use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::{
+ IVirtualMachineService::{
+ BnVirtualMachineService, IVirtualMachineService, VM_BINDER_SERVICE_PORT,
+ VM_STREAM_SERVICE_PORT,
+ },
};
use anyhow::{anyhow, bail, Context, Result};
-use ::binder::unstable_api::AsNative;
+use binder_common::{lazy_service::LazyServiceGuard, new_binder_exception};
use disk::QcowFile;
-use idsig::{V4Signature, HashAlgorithm};
-use log::{debug, error, warn, info};
+use idsig::{HashAlgorithm, V4Signature};
+use log::{debug, error, info, warn};
use microdroid_payload_config::VmPayloadConfig;
use rustutils::system_properties;
use std::convert::TryInto;
-use std::fs::{File, OpenOptions, create_dir};
+use std::fs::{create_dir, File, OpenOptions};
use std::io::{Error, ErrorKind, Write};
use std::num::NonZeroU32;
use std::os::unix::io::{FromRawFd, IntoRawFd};
@@ -556,11 +558,13 @@
#[derive(Debug)]
struct VirtualMachine {
instance: Arc<VmInstance>,
+ /// Keeps our service process running as long as this VM instance exists.
+ lazy_service_guard: LazyServiceGuard,
}
impl VirtualMachine {
fn create(instance: Arc<VmInstance>) -> Strong<dyn IVirtualMachine> {
- let binder = VirtualMachine { instance };
+ let binder = VirtualMachine { instance, lazy_service_guard: Default::default() };
BnVirtualMachine::new_binder(binder, BinderFeatures::default())
}
}
@@ -713,19 +717,12 @@
/// Store a strong VM reference.
fn debug_hold_vm(&mut self, vm: Strong<dyn IVirtualMachine>) {
self.debug_held_vms.push(vm);
- // Make sure our process is not shut down while we hold the VM reference
- // on behalf of the caller.
- force_lazy_services_persist(true);
}
/// Retrieve and remove a strong VM reference.
fn debug_drop_vm(&mut self, cid: i32) -> Option<Strong<dyn IVirtualMachine>> {
let pos = self.debug_held_vms.iter().position(|vm| vm.getCid() == Ok(cid))?;
let vm = self.debug_held_vms.swap_remove(pos);
- if self.debug_held_vms.is_empty() {
- // Once we no longer hold any VM references it is ok for our process to be shut down.
- force_lazy_services_persist(false);
- }
Some(vm)
}
}