Merge "Use a test helper executable to open files"
diff --git a/binder_common/lib.rs b/binder_common/lib.rs
index f2391e3..fa91f5a 100644
--- a/binder_common/lib.rs
+++ b/binder_common/lib.rs
@@ -17,6 +17,7 @@
//! Common items useful for binder clients and/or servers.
pub mod lazy_service;
+pub mod rpc_client;
pub mod rpc_server;
use binder::public_api::{ExceptionCode, Status};
diff --git a/binder_common/rpc_client.rs b/binder_common/rpc_client.rs
new file mode 100644
index 0000000..262a689
--- /dev/null
+++ b/binder_common/rpc_client.rs
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+//! Helpers for implementing an RPC Binder client.
+
+use binder::public_api::{StatusCode, Strong};
+use binder::unstable_api::{new_spibinder, AIBinder};
+
+/// Connects to a binder RPC server.
+pub fn connect_rpc_binder<T: binder::FromIBinder + ?Sized>(
+ cid: u32,
+ port: u32,
+) -> binder::Result<Strong<T>> {
+ // SAFETY: AIBinder returned by RpcClient has correct reference count, and the ownership can be
+ // safely taken by new_spibinder.
+ let ibinder = unsafe {
+ new_spibinder(binder_rpc_unstable_bindgen::RpcClient(cid, port) as *mut AIBinder)
+ };
+ if let Some(ibinder) = ibinder {
+ <T>::try_from(ibinder)
+ } else {
+ Err(StatusCode::BAD_VALUE)
+ }
+}
diff --git a/compos/libcompos_client/Android.bp b/compos/libcompos_client/Android.bp
index b6a4ef6..5528ea1 100644
--- a/compos/libcompos_client/Android.bp
+++ b/compos/libcompos_client/Android.bp
@@ -4,14 +4,12 @@
cc_library {
name: "libcompos_client",
- srcs: ["libcompos_client.cc"],
+ whole_static_libs: ["libcompos_client_ffi"],
min_sdk_version: "apex_inherit",
shared_libs: [
- "android.system.composd-ndk",
- "compos_aidl_interface-ndk",
- "libbase",
"libbinder_ndk",
"libbinder_rpc_unstable",
+ "libminijail",
],
export_include_dirs: ["include"],
stubs: {
@@ -25,3 +23,36 @@
"//art/odrefresh:__subpackages__",
],
}
+
+// TODO(203478530): Once rust_ffi supports stubs/symbol file, remove the wrapping cc_library above.
+rust_ffi {
+ name: "libcompos_client_ffi",
+ crate_name: "compos_client_ffi",
+ srcs: ["libcompos_client.rs"],
+ include_dirs: ["include"],
+ rustlibs: [
+ "android.system.composd-rust",
+ "compos_aidl_interface-rust",
+ "libandroid_logger",
+ "libanyhow",
+ "libbinder_common",
+ "libbinder_rs",
+ "libcompos_common",
+ "liblibc",
+ "liblog_rust",
+ "libminijail_rust",
+ "libnix",
+ "libscopeguard",
+ ],
+ prefer_rlib: true,
+ shared_libs: [
+ "libbinder_ndk",
+ ],
+ apex_available: [
+ "com.android.compos",
+ ],
+ visibility: [
+ "//packages/modules/Virtualization/compos:__subpackages__",
+ "//art/odrefresh:__subpackages__",
+ ],
+}
diff --git a/compos/libcompos_client/libcompos_client.cc b/compos/libcompos_client/libcompos_client.cc
deleted file mode 100644
index 147fcd0..0000000
--- a/compos/libcompos_client/libcompos_client.cc
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * 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.
- */
-
-#include "libcompos_client.h"
-
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <android/binder_auto_utils.h>
-#include <android/binder_manager.h>
-#include <binder/IInterface.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <binder_rpc_unstable.hpp>
-#include <memory>
-
-#include "aidl/android/system/composd/IIsolatedCompilationService.h"
-#include "aidl/com/android/compos/FdAnnotation.h"
-#include "aidl/com/android/compos/ICompOsService.h"
-
-using aidl::android::system::composd::IIsolatedCompilationService;
-using aidl::com::android::compos::FdAnnotation;
-using aidl::com::android::compos::ICompOsService;
-using android::base::Join;
-using android::base::Pipe;
-using android::base::unique_fd;
-
-namespace {
-
-constexpr unsigned int kCompsvcRpcPort = 6432;
-constexpr const char* kComposdServiceName = "android.system.composd";
-
-void ExecFdServer(const int* ro_fds, size_t ro_fds_num, const int* rw_fds, size_t rw_fds_num,
- unique_fd ready_fd) {
- // Holder of C Strings, with enough memory reserved to avoid reallocation. Otherwise,
- // `holder.rbegin()->c_str()` may become invalid.
- std::vector<std::string> holder;
- holder.reserve(ro_fds_num + rw_fds_num + 1 /* for --ready-fd */);
-
- std::vector<char const*> args = {"/apex/com.android.virt/bin/fd_server"};
- for (int i = 0; i < ro_fds_num; ++i) {
- args.emplace_back("--ro-fds");
- holder.emplace_back(std::to_string(*(ro_fds + i)));
- args.emplace_back(holder.rbegin()->c_str());
- }
- for (int i = 0; i < rw_fds_num; ++i) {
- args.emplace_back("--rw-fds");
- holder.emplace_back(std::to_string(*(rw_fds + i)));
- args.emplace_back(holder.rbegin()->c_str());
- }
- args.emplace_back("--ready-fd");
- holder.emplace_back(std::to_string(ready_fd.get()));
- args.emplace_back(holder.rbegin()->c_str());
-
- LOG(DEBUG) << "Starting fd_server, args: " << Join(args, ' ');
- args.emplace_back(nullptr);
- if (execv(args[0], const_cast<char* const*>(args.data())) < 0) {
- PLOG(ERROR) << "execv failed";
- }
-}
-
-class FileSharingSession final {
-public:
- static std::unique_ptr<FileSharingSession> Create(const int* ro_fds, size_t ro_fds_num,
- const int* rw_fds, size_t rw_fds_num) {
- // Create pipe for receiving a ready ping from fd_server.
- unique_fd pipe_read, pipe_write;
- if (!Pipe(&pipe_read, &pipe_write, /* flags= */ 0)) {
- PLOG(ERROR) << "Cannot create pipe";
- return nullptr;
- }
-
- pid_t pid = fork();
- if (pid < 0) {
- PLOG(ERROR) << "fork error";
- return nullptr;
- } else if (pid > 0) {
- pipe_write.reset();
-
- // 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.
- char c;
- read(pipe_read.get(), &c, sizeof(c));
-
- std::unique_ptr<FileSharingSession> session(new FileSharingSession(pid));
- return session;
- } else if (pid == 0) {
- pipe_read.reset();
- ExecFdServer(ro_fds, ro_fds_num, rw_fds, rw_fds_num, std::move(pipe_write));
- exit(EXIT_FAILURE);
- }
- return nullptr;
- }
-
- ~FileSharingSession() {
- if (kill(fd_server_pid_, SIGTERM) < 0) {
- PLOG(ERROR) << "Cannot kill fd_server (pid " << std::to_string(fd_server_pid_)
- << ") with SIGTERM. Retry with SIGKILL.";
- if (kill(fd_server_pid_, SIGKILL) < 0) {
- PLOG(ERROR) << "Still cannot terminate with SIGKILL. Give up.";
- // TODO: it may be the safest if we turn fd_server into a library to run in a
- // thread.
- }
- }
- }
-
-private:
- explicit FileSharingSession(pid_t pid) : fd_server_pid_(pid) {}
-
- pid_t fd_server_pid_;
-};
-
-int MakeRequestToVM(int cid, const uint8_t* marshaled, size_t size, const int* ro_fds,
- size_t ro_fds_num, const int* rw_fds, size_t rw_fds_num) {
- ndk::SpAIBinder binder(RpcClient(cid, kCompsvcRpcPort));
- std::shared_ptr<ICompOsService> service = ICompOsService::fromBinder(binder);
- if (!service) {
- LOG(ERROR) << "Cannot connect to the service";
- return -1;
- }
-
- std::unique_ptr<FileSharingSession> session_raii =
- FileSharingSession::Create(ro_fds, ro_fds_num, rw_fds, rw_fds_num);
- if (!session_raii) {
- LOG(ERROR) << "Cannot start to share FDs";
- return -1;
- }
-
- // Since the input from the C API are raw pointers, we need to duplicate them into vectors in
- // order to pass to the binder API.
- std::vector<uint8_t> duplicated_buffer(marshaled, marshaled + size);
- FdAnnotation fd_annotation = {
- .input_fds = std::vector<int>(ro_fds, ro_fds + ro_fds_num),
- .output_fds = std::vector<int>(rw_fds, rw_fds + rw_fds_num),
- };
- int8_t exit_code;
- ndk::ScopedAStatus status = service->compile(duplicated_buffer, fd_annotation, &exit_code);
- if (!status.isOk()) {
- LOG(ERROR) << "Compilation failed (exit " << std::to_string(exit_code)
- << "): " << status.getDescription();
- return -1;
- }
- return 0;
-}
-
-int MakeRequestToComposd(const uint8_t* marshaled, size_t size, const int* ro_fds,
- size_t ro_fds_num, const int* rw_fds, size_t rw_fds_num) {
- ndk::SpAIBinder binder(AServiceManager_getService(kComposdServiceName));
- std::shared_ptr<IIsolatedCompilationService> service =
- IIsolatedCompilationService::fromBinder(binder);
- if (!service) {
- LOG(ERROR) << "Cannot connect to the service";
- return -1;
- }
-
- auto session_raii = std::unique_ptr<FileSharingSession>(
- FileSharingSession::Create(ro_fds, ro_fds_num, rw_fds, rw_fds_num));
- if (!session_raii) {
- LOG(ERROR) << "Cannot start to share FDs";
- return -1;
- }
-
- // Since the input from the C API are raw pointers, we need to duplicate them into vectors in
- // order to pass to the binder API.
- std::vector<uint8_t> duplicated_buffer(marshaled, marshaled + size);
- FdAnnotation fd_annotation = {
- .input_fds = std::vector<int>(ro_fds, ro_fds + ro_fds_num),
- .output_fds = std::vector<int>(rw_fds, rw_fds + rw_fds_num),
- };
- int8_t exit_code;
- ndk::ScopedAStatus status = service->compile(duplicated_buffer, fd_annotation, &exit_code);
- if (!status.isOk()) {
- LOG(ERROR) << "Compilation failed (exit " << std::to_string(exit_code)
- << "): " << status.getDescription();
- return -1;
- }
- return 0;
-}
-
-} // namespace
-
-__BEGIN_DECLS
-
-int AComposClient_Request(int cid, const uint8_t* marshaled, size_t size, const int* ro_fds,
- size_t ro_fds_num, const int* rw_fds, size_t rw_fds_num) {
- if (cid == -1 /* VMADDR_CID_ANY */) {
- return MakeRequestToComposd(marshaled, size, ro_fds, ro_fds_num, rw_fds, rw_fds_num);
- } else {
- return MakeRequestToVM(cid, marshaled, size, ro_fds, ro_fds_num, rw_fds, rw_fds_num);
- }
-}
-
-__END_DECLS
diff --git a/compos/libcompos_client/libcompos_client.rs b/compos/libcompos_client/libcompos_client.rs
new file mode 100644
index 0000000..55d70a4
--- /dev/null
+++ b/compos/libcompos_client/libcompos_client.rs
@@ -0,0 +1,159 @@
+/*
+ * 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 library for a client to send requests to the CompOS service in the VM.
+
+use anyhow::{Context, Result};
+use binder_common::rpc_client::connect_rpc_binder;
+use libc::c_int;
+use log::{debug, error, warn};
+use minijail::Minijail;
+use nix::fcntl::OFlag;
+use nix::unistd::pipe2;
+use std::fs::File;
+use std::io::Read;
+use std::os::unix::io::{AsRawFd, FromRawFd};
+use std::path::Path;
+use std::slice::from_raw_parts;
+
+use android_system_composd::{
+ aidl::android::system::composd::IIsolatedCompilationService::IIsolatedCompilationService,
+ binder::wait_for_interface,
+};
+use compos_aidl_interface::aidl::com::android::compos::{
+ FdAnnotation::FdAnnotation, ICompOsService::ICompOsService,
+};
+use compos_aidl_interface::binder::Strong;
+use compos_common::{COMPOS_VSOCK_PORT, VMADDR_CID_ANY};
+
+const FD_SERVER_BIN: &str = "/apex/com.android.virt/bin/fd_server";
+
+fn get_composd() -> Result<Strong<dyn IIsolatedCompilationService>> {
+ wait_for_interface::<dyn IIsolatedCompilationService>("android.system.composd")
+ .context("Failed to find IIsolatedCompilationService")
+}
+
+fn spawn_fd_server(fd_annotation: &FdAnnotation, ready_file: File) -> Result<Minijail> {
+ let mut inheritable_fds = Vec::new();
+ let mut args = vec![FD_SERVER_BIN.to_string()];
+ for fd in &fd_annotation.input_fds {
+ args.push("--ro-fds".to_string());
+ args.push(fd.to_string());
+ inheritable_fds.push(*fd);
+ }
+ for fd in &fd_annotation.output_fds {
+ args.push("--rw-fds".to_string());
+ 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)?;
+ Ok(jail)
+}
+
+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_request(cid: c_int, marshaled: &[u8], fd_annotation: FdAnnotation) -> Result<c_int> {
+ // 1. Spawn a fd_server to serve remote read/write requests.
+ let (ready_read_fd, ready_write_fd) = create_pipe()?;
+ let fd_server_jail = spawn_fd_server(&fd_annotation, ready_write_fd)?;
+ 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(_)) {
+ warn!("Failed to kill fd_server: {}", e);
+ }
+ }
+ });
+
+ // 2. Send the marshaled request the remote.
+ let cid = cid as u32;
+ let result = if cid == VMADDR_CID_ANY {
+ // Sentinel value that indicates we should use composd
+ let composd = get_composd()?;
+ wait_for_fd_server_ready(ready_read_fd)?;
+ composd.compile(marshaled, &fd_annotation)
+ } else {
+ // Call directly into the VM
+ let compos_vm = connect_rpc_binder::<dyn ICompOsService>(cid, COMPOS_VSOCK_PORT)
+ .context("Cannot connect to RPC binder")?;
+ wait_for_fd_server_ready(ready_read_fd)?;
+ compos_vm.compile(marshaled, &fd_annotation)
+ };
+ let result = result.context("Binder call failed")?;
+
+ // Be explicit about the lifetime, which should last at least until the task is finished.
+ drop(fd_server_lifetime);
+
+ Ok(c_int::from(result))
+}
+
+/// A public C API. See libcompos_client.h for the canonical doc.
+///
+/// # Safety
+///
+/// The client must provide legitimate pointers with correct sizes to the backing arrays.
+#[no_mangle]
+pub unsafe extern "C" fn AComposClient_Request(
+ cid: c_int,
+ marshaled: *const u8,
+ size: usize,
+ ro_fds: *const c_int,
+ ro_fds_num: usize,
+ rw_fds: *const c_int,
+ rw_fds_num: usize,
+) -> c_int {
+ if marshaled.is_null() || ro_fds.is_null() || rw_fds.is_null() {
+ error!("Argument pointers should not be null");
+ return -1;
+ }
+
+ // The unsafe parts.
+ let ro_fd_slice = from_raw_parts(ro_fds, ro_fds_num);
+ let rw_fd_slice = from_raw_parts(rw_fds, rw_fds_num);
+ let marshaled_slice = from_raw_parts(marshaled, size);
+
+ let fd_annotation =
+ FdAnnotation { input_fds: ro_fd_slice.to_vec(), output_fds: rw_fd_slice.to_vec() };
+
+ match try_request(cid, marshaled_slice, fd_annotation) {
+ Ok(exit_code) => exit_code,
+ Err(e) => {
+ error!("AComposClient_Request failed: {:?}", e);
+ -1
+ }
+ }
+}
diff --git a/microdroid/Android.bp b/microdroid/Android.bp
index 425657f..3665687 100644
--- a/microdroid/Android.bp
+++ b/microdroid/Android.bp
@@ -51,9 +51,9 @@
"init_second_stage",
"microdroid_build_prop",
"microdroid_init_rc",
+ "microdroid_ueventd_rc",
"microdroid_launcher",
- "ueventd.rc",
"libbinder",
"libbinder_ndk",
"libstdc++",
@@ -136,6 +136,13 @@
installable: false, // avoid collision with system partition's init.rc
}
+prebuilt_etc {
+ name: "microdroid_ueventd_rc",
+ filename: "ueventd.rc",
+ src: "ueventd.rc",
+ installable: false, // avoid collision with system partition's ueventd.rc
+}
+
prebuilt_root {
name: "microdroid_build_prop",
filename: "build.prop",
@@ -225,7 +232,15 @@
},
x86_64: {
kernel_prebuilt: ":kernel_prebuilts-5.10-x86_64",
- cmdline: microdroid_boot_cmdline + ["acpi=noirq"],
+ cmdline: microdroid_boot_cmdline + [
+ // console=none is to work around the x86 specific u-boot behavior which when
+ // console= option is not found in the kernel commandline console=ttyS0 is
+ // automatically added. By adding console=none, we can prevent u-boot from doing
+ // that. Note that console is set to hvc0 by bootconfig if the VM is configured as
+ // debuggable.
+ "console=none",
+ "acpi=noirq",
+ ],
},
},
diff --git a/microdroid/bootconfig.full_debuggable b/microdroid/bootconfig.full_debuggable
index f6afdcf..0d0457c 100644
--- a/microdroid/bootconfig.full_debuggable
+++ b/microdroid/bootconfig.full_debuggable
@@ -3,6 +3,7 @@
# Kernel message is exported.
kernel.printk.devkmsg=on
+kernel.console=hvc0
# ADB is supported and rooting is possible. Note that
# ro.adb.secure is still 0 (see build.prop) which means that adbd is started
diff --git a/microdroid/bootconfig.x86_64 b/microdroid/bootconfig.x86_64
index 75e4a80..20d64f7 100644
--- a/microdroid/bootconfig.x86_64
+++ b/microdroid/bootconfig.x86_64
@@ -1 +1 @@
-androidboot.boot_devices = pci0000:00/0000:00:01.0,pci0000:00/0000:00:02.0,pci0000:00/0000:00:03.0
+androidboot.boot_devices = pci0000:00/0000:00:02.0,pci0000:00/0000:00:03.0,pci0000:00/0000:00:04.0
diff --git a/microdroid/ueventd.rc b/microdroid/ueventd.rc
new file mode 100644
index 0000000..271e134
--- /dev/null
+++ b/microdroid/ueventd.rc
@@ -0,0 +1,26 @@
+uevent_socket_rcvbuf_size 16M
+
+subsystem dma_heap
+ devname uevent_devpath
+ dirname /dev/dma_heap
+
+/dev/null 0666 root root
+/dev/zero 0666 root root
+/dev/full 0666 root root
+/dev/ptmx 0666 root root
+/dev/tty 0666 root root
+/dev/random 0666 root root
+/dev/urandom 0666 root root
+/dev/ashmem* 0666 root root
+/dev/binder 0666 root root
+/dev/hwbinder 0666 root root
+/dev/vndbinder 0666 root root
+
+/dev/pmsg0 0222 root log
+/dev/dma_heap/system 0444 system system
+/dev/dma_heap/system-uncached 0444 system system
+/dev/dma_heap/system-secure 0444 system system
+
+# these should not be world writable
+/dev/rtc0 0640 system system
+/dev/tty0 0660 root system
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index dc72c95..177a0db 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -240,13 +240,13 @@
/// virtualizationservice in the host side.
fn exec_task(task: &Task, service: &Strong<dyn IVirtualMachineService>) -> Result<()> {
info!("executing main task {:?}...", task);
- let mut child = build_command(task)?.spawn()?;
+ let mut command = build_command(task)?;
let local_cid = get_local_cid()?;
info!("notifying payload started");
service.notifyPayloadStarted(local_cid as i32)?;
- let exit_status = child.wait()?;
+ let exit_status = command.spawn()?.wait()?;
if let Some(code) = exit_status.code() {
info!("notifying payload finished");
service.notifyPayloadFinished(local_cid as i32, code)?;
diff --git a/virtualizationservice/src/crosvm.rs b/virtualizationservice/src/crosvm.rs
index 38e5bf3..4844657 100644
--- a/virtualizationservice/src/crosvm.rs
+++ b/virtualizationservice/src/crosvm.rs
@@ -238,12 +238,25 @@
command.arg("--mem").arg(memory_mib.to_string());
}
- if let Some(log_fd) = config.log_fd {
+ // Setup the serial devices.
+ // 1. uart device: used as the output device by bootloaders and as early console by linux
+ // 2. virtio-console device: used as the console device
+ //
+ // When log_fd is not specified, the devices are attached to sink, which means what's written
+ // there is discarded.
+ //
+ // Warning: Adding more serial devices requires you to shift the PCI device ID of the boot
+ // disks in bootconfig.x86_64. This is because x86 crosvm puts serial devices and the block
+ // devices in the same PCI bus and serial devices comes before the block devices. Arm crosvm
+ // doesn't have the issue.
+ let backend = if let Some(log_fd) = config.log_fd {
command.stdout(log_fd);
+ "stdout"
} else {
- // Ignore console output.
- command.arg("--serial=type=sink");
- }
+ "sink"
+ };
+ command.arg(format!("--serial=type={},hardware=serial", backend));
+ command.arg(format!("--serial=type={},hardware=virtio-console", backend));
// Keep track of what file descriptors should be mapped to the crosvm process.
let mut preserved_fds = config.indirect_files.iter().map(|file| file.as_raw_fd()).collect();
diff --git a/virtualizationservice/src/payload.rs b/virtualizationservice/src/payload.rs
index 4c71c37..a59afd5 100644
--- a/virtualizationservice/src/payload.rs
+++ b/virtualizationservice/src/payload.rs
@@ -21,7 +21,7 @@
};
use android_system_virtualizationservice::binder::ParcelFileDescriptor;
use anyhow::{anyhow, Context, Result};
-use binder::{wait_for_interface, Strong};
+use binder::wait_for_interface;
use log::{error, info};
use microdroid_metadata::{ApexPayload, ApkPayload, Metadata};
use microdroid_payload_config::{ApexConfig, VmPayloadConfig};
@@ -108,27 +108,28 @@
}
struct PackageManager {
- service: Strong<dyn IPackageManagerNative>,
// TODO(b/199146189) use IPackageManagerNative
apex_info_list: &'static ApexInfoList,
}
impl PackageManager {
fn new() -> Result<Self> {
- let service = wait_for_interface(PACKAGE_MANAGER_NATIVE_SERVICE)
- .context("Failed to find PackageManager")?;
let apex_info_list = ApexInfoList::load()?;
- Ok(Self { service, apex_info_list })
+ Ok(Self { apex_info_list })
}
fn get_apex_list(&self, prefer_staged: bool) -> Result<ApexInfoList> {
+ // get the list of active apexes
let mut list = self.apex_info_list.clone();
+ // When prefer_staged, we override ApexInfo by consulting "package_native"
if prefer_staged {
- // When prefer_staged, we override ApexInfo by consulting "package_native"
- let staged = self.service.getStagedApexModuleNames()?;
+ let pm =
+ wait_for_interface::<dyn IPackageManagerNative>(PACKAGE_MANAGER_NATIVE_SERVICE)
+ .context("Failed to get service when prefer_staged is set.")?;
+ let staged = pm.getStagedApexModuleNames()?;
for apex_info in list.list.iter_mut() {
if staged.contains(&apex_info.name) {
- let staged_apex_info = self.service.getStagedApexInfo(&apex_info.name)?;
+ let staged_apex_info = pm.getStagedApexInfo(&apex_info.name)?;
if let Some(staged_apex_info) = staged_apex_info {
apex_info.path = PathBuf::from(staged_apex_info.diskImagePath);
// TODO(b/201788989) copy bootclasspath/systemserverclasspath