Merge "Ignore identity if the debug policy is turned on"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 33498d3..c967473 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -35,6 +35,9 @@
"path": "packages/modules/Virtualization/apkdmverity"
},
{
+ "path": "packages/modules/Virtualization/avmd"
+ },
+ {
"path": "packages/modules/Virtualization/virtualizationservice"
},
{
diff --git a/authfs/fd_server/src/aidl.rs b/authfs/fd_server/src/aidl.rs
index 3a3cdb2..9a60bf7 100644
--- a/authfs/fd_server/src/aidl.rs
+++ b/authfs/fd_server/src/aidl.rs
@@ -36,13 +36,12 @@
use authfs_aidl_interface::aidl::com::android::virt::fs::IVirtFdService::{
BnVirtFdService, FsStat::FsStat, IVirtFdService, MAX_REQUESTING_DATA,
};
-use authfs_aidl_interface::binder::{
- BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status, StatusCode, Strong,
-};
use authfs_fsverity_metadata::{
get_fsverity_metadata_path, parse_fsverity_metadata, FSVerityMetadata,
};
-use binder_common::{new_binder_exception, new_binder_service_specific_error};
+use binder::{
+ BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status, StatusCode, Strong,
+};
/// Bitflags of forbidden file mode, e.g. setuid, setgid and sticky bit.
const FORBIDDEN_MODES: Mode = Mode::from_bits_truncate(!0o777);
@@ -107,9 +106,12 @@
entry.insert(new_fd_config);
Ok(new_fd)
} else {
- Err(new_binder_exception(
+ Err(Status::new_exception_str(
ExceptionCode::ILLEGAL_STATE,
- format!("The newly created FD {} is already in the pool unexpectedly", new_fd),
+ Some(format!(
+ "The newly created FD {} is already in the pool unexpectedly",
+ new_fd
+ )),
))
}
}
@@ -173,9 +175,9 @@
if let Some(signature) = &metadata.signature {
Ok(signature.clone())
} else {
- Err(new_binder_exception(
- ExceptionCode::SERVICE_SPECIFIC,
- "metadata doesn't contain a signature",
+ Err(Status::new_service_specific_error_str(
+ -1,
+ Some("metadata doesn't contain a signature"),
))
}
} else {
@@ -395,7 +397,7 @@
}
fn new_errno_error(errno: Errno) -> Status {
- new_binder_service_specific_error(errno as i32, errno.desc())
+ Status::new_service_specific_error_str(errno as i32, Some(errno.desc()))
}
fn open_readonly_at(dir_fd: RawFd, path: &Path) -> nix::Result<File> {
diff --git a/authfs/service/Android.bp b/authfs/service/Android.bp
index 6c32c67..943db35 100644
--- a/authfs/service/Android.bp
+++ b/authfs/service/Android.bp
@@ -12,7 +12,6 @@
"authfs_aidl_interface-rust",
"libandroid_logger",
"libanyhow",
- "libbinder_common",
"libbinder_rs",
"liblibc",
"liblog_rust",
diff --git a/authfs/service/src/authfs.rs b/authfs/service/src/authfs.rs
index c941360..3e8e0e0 100644
--- a/authfs/service/src/authfs.rs
+++ b/authfs/service/src/authfs.rs
@@ -31,10 +31,7 @@
OutputDirFdAnnotation::OutputDirFdAnnotation, OutputFdAnnotation::OutputFdAnnotation,
};
use authfs_aidl_interface::aidl::com::android::virt::fs::IAuthFs::{BnAuthFs, IAuthFs};
-use authfs_aidl_interface::binder::{
- self, BinderFeatures, ExceptionCode, Interface, ParcelFileDescriptor, Strong,
-};
-use binder_common::new_binder_exception;
+use binder::{self, BinderFeatures, Interface, ParcelFileDescriptor, Status, Strong};
const AUTHFS_BIN: &str = "/system/bin/authfs";
const AUTHFS_SETUP_POLL_INTERVAL_MS: Duration = Duration::from_millis(50);
@@ -60,9 +57,9 @@
let mut path = PathBuf::from(&self.mountpoint);
path.push(remote_fd_name.to_string());
let file = OpenOptions::new().read(true).write(writable).open(&path).map_err(|e| {
- new_binder_exception(
- ExceptionCode::SERVICE_SPECIFIC,
- format!("failed to open {:?} on authfs: {}", &path, e),
+ Status::new_service_specific_error_str(
+ -1,
+ Some(format!("failed to open {:?} on authfs: {}", &path, e)),
)
})?;
Ok(ParcelFileDescriptor::new(file))
@@ -72,7 +69,7 @@
if let Some(s) = self.mountpoint.to_str() {
Ok(s.to_string())
} else {
- Err(new_binder_exception(ExceptionCode::SERVICE_SPECIFIC, "Bad string encoding"))
+ Err(Status::new_service_specific_error_str(-1, Some("Bad string encoding")))
}
}
}
diff --git a/authfs/service/src/main.rs b/authfs/service/src/main.rs
index 890e108..77cac9a 100644
--- a/authfs/service/src/main.rs
+++ b/authfs/service/src/main.rs
@@ -33,10 +33,9 @@
use authfs_aidl_interface::aidl::com::android::virt::fs::IAuthFsService::{
BnAuthFsService, IAuthFsService,
};
-use authfs_aidl_interface::binder::{
- self, add_service, BinderFeatures, ExceptionCode, Interface, ProcessState, Strong,
+use binder::{
+ self, add_service, BinderFeatures, ExceptionCode, Interface, ProcessState, Status, Strong,
};
-use binder_common::new_binder_exception;
const SERVICE_NAME: &str = "authfs_service";
const SERVICE_ROOT: &str = "/data/misc/authfs";
@@ -57,16 +56,16 @@
// The directory is supposed to be deleted when `AuthFs` is dropped.
create_dir(&mountpoint).map_err(|e| {
- new_binder_exception(
- ExceptionCode::SERVICE_SPECIFIC,
- format!("Cannot create mount directory {:?}: {:?}", &mountpoint, e),
+ Status::new_service_specific_error_str(
+ -1,
+ Some(format!("Cannot create mount directory {:?}: {:?}", &mountpoint, e)),
)
})?;
authfs::AuthFs::mount_and_wait(mountpoint, config, self.debuggable).map_err(|e| {
- new_binder_exception(
- ExceptionCode::SERVICE_SPECIFIC,
- format!("mount_and_wait failed: {:?}", e),
+ Status::new_service_specific_error_str(
+ -1,
+ Some(format!("mount_and_wait failed: {:?}", e)),
)
})
}
@@ -80,9 +79,9 @@
fn validate(&self, config: &AuthFsConfig) -> binder::Result<()> {
if config.port < 0 {
- return Err(new_binder_exception(
+ return Err(Status::new_exception_str(
ExceptionCode::ILLEGAL_ARGUMENT,
- format!("Invalid port: {}", config.port),
+ Some(format!("Invalid port: {}", config.port)),
));
}
Ok(())
diff --git a/authfs/src/file.rs b/authfs/src/file.rs
index d9f8964..df52a0e 100644
--- a/authfs/src/file.rs
+++ b/authfs/src/file.rs
@@ -8,8 +8,7 @@
use crate::common::{divide_roundup, CHUNK_SIZE};
use authfs_aidl_interface::aidl::com::android::virt::fs::IVirtFdService::IVirtFdService;
-use authfs_aidl_interface::binder::{Status, Strong};
-use binder::StatusCode;
+use binder::{Status, StatusCode, Strong};
use binder_common::rpc_client::connect_rpc_binder;
use std::convert::TryFrom;
use std::io;
diff --git a/avmd/Android.bp b/avmd/Android.bp
index 9f0b28b..b09bed5 100644
--- a/avmd/Android.bp
+++ b/avmd/Android.bp
@@ -22,7 +22,6 @@
rust_binary {
name: "avmdtool",
srcs: ["src/main.rs"],
- required: ["avbtool"],
host_supported: true,
prefer_rlib: true,
rustlibs: [
@@ -36,3 +35,16 @@
"libvbmeta_rust",
],
}
+
+rust_test_host {
+ name: "avmdtool_tests",
+ srcs: ["tests/*_test.rs"],
+ test_suites: ["general-tests"],
+ prefer_rlib: true,
+ data: ["tests/data/*"],
+ data_bins: ["avmdtool"],
+ data_libs: [
+ "libcrypto",
+ "libz",
+ ],
+}
diff --git a/avmd/TEST_MAPPING b/avmd/TEST_MAPPING
new file mode 100644
index 0000000..dd687fe
--- /dev/null
+++ b/avmd/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit" : [
+ {
+ "name" : "avmdtool_tests"
+ }
+ ]
+}
diff --git a/avmd/tests/avmdtool_test.rs b/avmd/tests/avmdtool_test.rs
new file mode 100644
index 0000000..d93cb6f
--- /dev/null
+++ b/avmd/tests/avmdtool_test.rs
@@ -0,0 +1,34 @@
+// 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.
+
+//! Tests for avmdtool.
+
+use std::fs;
+use std::process::Command;
+
+#[test]
+fn test_dump() {
+ // test.avmd is generated with
+ // ```
+ // avmdtool create /tmp/test.amvd \
+ // --apex-payload microdroid vbmeta ./libs/apexutil/tests/data/test.apex \
+ // --apk microdroid_manager apk \
+ // ./libs/apkverify/tests/data/v3-only-with-rsa-pkcs1-sha256-4096.apk \
+ // --apk microdroid_manager extra-apk ./libs/apkverify/tests/data/v3-only-with-stamp.apk
+ //```
+ let output =
+ Command::new("./avmdtool").args(["dump", "tests/data/test.avmd"]).output().unwrap();
+ assert!(output.status.success());
+ assert_eq!(output.stdout, fs::read("tests/data/test.avmd.dump").unwrap());
+}
diff --git a/avmd/tests/data/test.avmd b/avmd/tests/data/test.avmd
new file mode 100644
index 0000000..52e634f
--- /dev/null
+++ b/avmd/tests/data/test.avmd
Binary files differ
diff --git a/avmd/tests/data/test.avmd.dump b/avmd/tests/data/test.avmd.dump
new file mode 100644
index 0000000..a63a151
--- /dev/null
+++ b/avmd/tests/data/test.avmd.dump
@@ -0,0 +1,16 @@
+Descriptors:
+ VBMeta descriptor:
+ namespace: microdroid
+ name: vbmeta
+ vbmeta digest: 296e32a76544de9da01713e471403ab4667705ad527bb4f1fac0cf61e7ce122d
+ APK descriptor:
+ namespace: microdroid_manager
+ name: apk
+ Signing algorithm ID: 0x103
+ APK digest: 0df2426ea33aedaf495d88e5be0c6a1663ff0a81c5ed12d5b2929ae4b4300f2f
+ APK descriptor:
+ namespace: microdroid_manager
+ name: extra-apk
+ Signing algorithm ID: 0x201
+ APK digest: 626bb647c0089717a7ffa52fd8e845f9403d5e27f7a5a8752e47b3345fb82f5c
+
diff --git a/compos/common/Android.bp b/compos/common/Android.bp
index 3c3397d..23a1eb9 100644
--- a/compos/common/Android.bp
+++ b/compos/common/Android.bp
@@ -11,7 +11,7 @@
"android.system.virtualizationservice-rust",
"compos_aidl_interface-rust",
"libanyhow",
- "libbinder_common",
+ "libbinder_rs",
"liblazy_static",
"liblog_rust",
"libnested_virt",
diff --git a/compos/common/binder.rs b/compos/common/binder.rs
index 45139f3..d3550f7 100644
--- a/compos/common/binder.rs
+++ b/compos/common/binder.rs
@@ -16,8 +16,7 @@
//! Helper for converting Error types to what Binder expects
-use android_system_virtualizationservice::binder::{ExceptionCode, Result as BinderResult};
-use binder_common::new_binder_exception;
+use binder::{Result as BinderResult, Status};
use log::warn;
use std::fmt::Debug;
@@ -28,6 +27,6 @@
result.map_err(|e| {
let message = format!("{:?}", e);
warn!("Returning binder error: {}", &message);
- new_binder_exception(ExceptionCode::SERVICE_SPECIFIC, message)
+ Status::new_service_specific_error_str(-1, Some(message))
})
}
diff --git a/compos/common/compos_client.rs b/compos/common/compos_client.rs
index cd1ece4..770f489 100644
--- a/compos/common/compos_client.rs
+++ b/compos/common/compos_client.rs
@@ -19,16 +19,12 @@
use crate::timeouts::TIMEOUTS;
use crate::{COMPOS_APEX_ROOT, COMPOS_DATA_ROOT, COMPOS_VSOCK_PORT, DEFAULT_VM_CONFIG_PATH};
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
- DeathReason::DeathReason,
- IVirtualMachineCallback::{BnVirtualMachineCallback, IVirtualMachineCallback},
IVirtualizationService::IVirtualizationService,
VirtualMachineAppConfig::{DebugLevel::DebugLevel, VirtualMachineAppConfig},
VirtualMachineConfig::VirtualMachineConfig,
};
-use android_system_virtualizationservice::binder::{
- BinderFeatures, Interface, ParcelFileDescriptor, Result as BinderResult, Strong,
-};
use anyhow::{bail, Context, Result};
+use binder::{ParcelFileDescriptor, Strong};
use compos_aidl_interface::aidl::com::android::compos::ICompOsService::ICompOsService;
use log::{info, warn};
use rustutils::system_properties;
@@ -37,7 +33,7 @@
use std::num::NonZeroU32;
use std::path::{Path, PathBuf};
use std::thread;
-use vmclient::{VmInstance, VmWaitError};
+use vmclient::{DeathReason, VmInstance, VmWaitError};
/// This owns an instance of the CompOS VM.
pub struct ComposClient(VmInstance);
@@ -119,13 +115,10 @@
taskProfiles: parameters.task_profiles.clone(),
});
- let instance = VmInstance::create(service, &config, console_fd, log_fd)
+ let callback = Box::new(Callback {});
+ let instance = VmInstance::create(service, &config, console_fd, log_fd, Some(callback))
.context("Failed to create VM")?;
- let callback =
- BnVirtualMachineCallback::new_binder(VmCallback(), BinderFeatures::default());
- instance.vm.registerCallback(&callback)?;
-
instance.start()?;
let ready = instance.wait_until_ready(TIMEOUTS.vm_max_time_to_ready);
@@ -163,7 +156,7 @@
fn wait_for_shutdown(self) {
let death_reason = self.0.wait_for_death_with_timeout(TIMEOUTS.vm_max_time_to_exit);
match death_reason {
- Some(vmclient::DeathReason::Shutdown) => info!("VM has exited normally"),
+ Some(DeathReason::Shutdown) => info!("VM has exited normally"),
Some(reason) => warn!("VM died with reason {:?}", reason),
None => warn!("VM failed to exit, dropping"),
}
@@ -228,53 +221,36 @@
bail!("No VM support available")
}
-struct VmCallback();
-
-impl Interface for VmCallback {}
-
-impl IVirtualMachineCallback for VmCallback {
- fn onDied(&self, cid: i32, reason: DeathReason) -> BinderResult<()> {
- log::warn!("VM died, cid = {}, reason = {:?}", cid, reason);
- Ok(())
- }
-
- fn onPayloadStarted(
- &self,
- cid: i32,
- stream: Option<&ParcelFileDescriptor>,
- ) -> BinderResult<()> {
- if let Some(pfd) = stream {
- if let Err(e) = start_logging(pfd) {
+struct Callback {}
+impl vmclient::VmCallback for Callback {
+ fn on_payload_started(&self, cid: i32, stream: Option<&File>) {
+ if let Some(file) = stream {
+ if let Err(e) = start_logging(file) {
warn!("Can't log vm output: {}", e);
};
}
log::info!("VM payload started, cid = {}", cid);
- Ok(())
}
- fn onPayloadReady(&self, cid: i32) -> BinderResult<()> {
+ fn on_payload_ready(&self, cid: i32) {
log::info!("VM payload ready, cid = {}", cid);
- Ok(())
}
- fn onPayloadFinished(&self, cid: i32, exit_code: i32) -> BinderResult<()> {
+ fn on_payload_finished(&self, cid: i32, exit_code: i32) {
log::warn!("VM payload finished, cid = {}, exit code = {}", cid, exit_code);
- Ok(())
}
- fn onError(&self, cid: i32, error_code: i32, message: &str) -> BinderResult<()> {
- log::warn!("VM error, cid = {}, error code = {}, message = {}", cid, error_code, message,);
- Ok(())
+ fn on_error(&self, cid: i32, error_code: i32, message: &str) {
+ log::warn!("VM error, cid = {}, error code = {}, message = {}", cid, error_code, message);
}
- fn onRamdump(&self, _cid: i32, _ramdump: &ParcelFileDescriptor) -> BinderResult<()> {
- // TODO(b/238295267) send this to tombstone?
- Ok(())
+ fn on_died(&self, cid: i32, death_reason: DeathReason) {
+ log::warn!("VM died, cid = {}, reason = {:?}", cid, death_reason);
}
}
-fn start_logging(pfd: &ParcelFileDescriptor) -> Result<()> {
- let reader = BufReader::new(pfd.as_ref().try_clone().context("Cloning fd failed")?);
+fn start_logging(file: &File) -> Result<()> {
+ let reader = BufReader::new(file.try_clone().context("Cloning file failed")?);
thread::spawn(move || {
for line in reader.lines() {
match line {
diff --git a/compos/composd/src/composd_main.rs b/compos/composd/src/composd_main.rs
index ebcd689..5315828 100644
--- a/compos/composd/src/composd_main.rs
+++ b/compos/composd/src/composd_main.rs
@@ -25,8 +25,8 @@
mod service;
use crate::instance_manager::InstanceManager;
-use android_system_composd::binder::{register_lazy_service, ProcessState};
use anyhow::{Context, Result};
+use binder::{register_lazy_service, ProcessState};
use log::{error, info};
use std::panic;
use std::sync::Arc;
diff --git a/compos/composd/src/instance_manager.rs b/compos/composd/src/instance_manager.rs
index 9a0935c..75671d7 100644
--- a/compos/composd/src/instance_manager.rs
+++ b/compos/composd/src/instance_manager.rs
@@ -20,7 +20,7 @@
use crate::instance_starter::{CompOsInstance, InstanceStarter};
use android_system_virtualizationservice::aidl::android::system::virtualizationservice;
use anyhow::{bail, Result};
-use compos_aidl_interface::binder::Strong;
+use binder::Strong;
use compos_common::compos_client::VmParameters;
use compos_common::{
CURRENT_INSTANCE_DIR, DEX2OAT_CPU_SET_PROP_NAME, DEX2OAT_THREADS_PROP_NAME,
diff --git a/compos/composd/src/instance_starter.rs b/compos/composd/src/instance_starter.rs
index 111c719..aaa4695 100644
--- a/compos/composd/src/instance_starter.rs
+++ b/compos/composd/src/instance_starter.rs
@@ -21,9 +21,8 @@
IVirtualizationService::IVirtualizationService, PartitionType::PartitionType,
};
use anyhow::{Context, Result};
-use binder_common::lazy_service::LazyServiceGuard;
+use binder::{LazyServiceGuard, ParcelFileDescriptor, Strong};
use compos_aidl_interface::aidl::com::android::compos::ICompOsService::ICompOsService;
-use compos_aidl_interface::binder::{ParcelFileDescriptor, Strong};
use compos_common::compos_client::{ComposClient, VmParameters};
use compos_common::{COMPOS_DATA_ROOT, IDSIG_FILE, IDSIG_MANIFEST_APK_FILE, INSTANCE_IMAGE_FILE};
use log::info;
diff --git a/compos/composd/src/odrefresh_task.rs b/compos/composd/src/odrefresh_task.rs
index 8fd574c..100fc50 100644
--- a/compos/composd/src/odrefresh_task.rs
+++ b/compos/composd/src/odrefresh_task.rs
@@ -22,8 +22,8 @@
ICompilationTask::ICompilationTask,
ICompilationTaskCallback::{FailureReason::FailureReason, ICompilationTaskCallback},
};
-use android_system_composd::binder::{Interface, Result as BinderResult, Strong};
use anyhow::{Context, Result};
+use binder::{Interface, Result as BinderResult, Strong};
use compos_aidl_interface::aidl::com::android::compos::ICompOsService::{
CompilationMode::CompilationMode, ICompOsService,
};
diff --git a/compos/composd/src/service.rs b/compos/composd/src/service.rs
index a9b8202..49cfd3a 100644
--- a/compos/composd/src/service.rs
+++ b/compos/composd/src/service.rs
@@ -26,10 +26,8 @@
ApexSource::ApexSource, BnIsolatedCompilationService, IIsolatedCompilationService,
},
};
-use android_system_composd::binder::{
- self, BinderFeatures, ExceptionCode, Interface, Status, Strong, ThreadState,
-};
use anyhow::{Context, Result};
+use binder::{self, BinderFeatures, ExceptionCode, Interface, Status, Strong, ThreadState};
use compos_aidl_interface::aidl::com::android::compos::ICompOsService::CompilationMode::CompilationMode;
use compos_common::binder::to_binder_result;
use compos_common::odrefresh::{PENDING_ARTIFACTS_SUBDIR, TEST_ARTIFACTS_SUBDIR};
diff --git a/compos/src/compilation.rs b/compos/src/compilation.rs
index e14cd94..ab228e1 100644
--- a/compos/src/compilation.rs
+++ b/compos/src/compilation.rs
@@ -32,7 +32,7 @@
},
IAuthFsService::IAuthFsService,
};
-use authfs_aidl_interface::binder::Strong;
+use binder::Strong;
use compos_aidl_interface::aidl::com::android::compos::ICompOsService::CompilationMode::CompilationMode;
use compos_common::odrefresh::ExitCode;
diff --git a/compos/src/compsvc.rs b/compos/src/compsvc.rs
index 5d58221..baf444e 100644
--- a/compos/src/compsvc.rs
+++ b/compos/src/compsvc.rs
@@ -19,7 +19,6 @@
//! actual compiler.
use anyhow::{bail, Context, Result};
-use binder_common::new_binder_exception;
use log::{error, info};
use rustutils::system_properties;
use std::default::Default;
@@ -31,12 +30,10 @@
use crate::artifact_signer::ArtifactSigner;
use crate::compilation::{odrefresh, OdrefreshContext};
use crate::compos_key;
+use binder::{BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status, Strong};
use compos_aidl_interface::aidl::com::android::compos::ICompOsService::{
BnCompOsService, CompilationMode::CompilationMode, ICompOsService,
};
-use compos_aidl_interface::binder::{
- BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Strong,
-};
use compos_common::binder::to_binder_result;
use compos_common::odrefresh::{is_system_property_interesting, ODREFRESH_PATH};
@@ -67,28 +64,28 @@
fn initializeSystemProperties(&self, names: &[String], values: &[String]) -> BinderResult<()> {
let mut initialized = self.initialized.write().unwrap();
if initialized.is_some() {
- return Err(new_binder_exception(
+ return Err(Status::new_exception_str(
ExceptionCode::ILLEGAL_STATE,
- format!("Already initialized: {:?}", initialized),
+ Some(format!("Already initialized: {:?}", initialized)),
));
}
*initialized = Some(false);
if names.len() != values.len() {
- return Err(new_binder_exception(
+ return Err(Status::new_exception_str(
ExceptionCode::ILLEGAL_ARGUMENT,
- format!(
+ Some(format!(
"Received inconsistent number of keys ({}) and values ({})",
names.len(),
values.len()
- ),
+ )),
));
}
for (name, value) in zip(names, values) {
if !is_system_property_interesting(name) {
- return Err(new_binder_exception(
+ return Err(Status::new_exception_str(
ExceptionCode::ILLEGAL_ARGUMENT,
- format!("Received invalid system property {}", &name),
+ Some(format!("Received invalid system property {}", &name)),
));
}
let result = system_properties::write(name, value);
@@ -113,9 +110,9 @@
) -> BinderResult<i8> {
let initialized = *self.initialized.read().unwrap();
if !initialized.unwrap_or(false) {
- return Err(new_binder_exception(
+ return Err(Status::new_exception_str(
ExceptionCode::ILLEGAL_STATE,
- "Service has not been initialized",
+ Some("Service has not been initialized"),
));
}
@@ -129,7 +126,7 @@
system_server_compiler_filter,
))?;
- let authfs_service = authfs_aidl_interface::binder::get_interface(AUTHFS_SERVICE_NAME)?;
+ let authfs_service = binder::get_interface(AUTHFS_SERVICE_NAME)?;
let exit_code = to_binder_result(
odrefresh(&self.odrefresh_path, context, authfs_service, |output_dir| {
// authfs only shows us the files we created, so it's ok to just sign everything
diff --git a/compos/verify/verify.rs b/compos/verify/verify.rs
index 224cde7..2ece8f5 100644
--- a/compos/verify/verify.rs
+++ b/compos/verify/verify.rs
@@ -19,7 +19,7 @@
use android_logger::LogId;
use anyhow::{bail, Context, Result};
-use compos_aidl_interface::binder::ProcessState;
+use binder::ProcessState;
use compos_common::compos_client::{ComposClient, VmParameters};
use compos_common::odrefresh::{
CURRENT_ARTIFACTS_SUBDIR, ODREFRESH_OUTPUT_ROOT_DIR, PENDING_ARTIFACTS_SUBDIR,
diff --git a/libs/binder_common/Android.bp b/libs/binder_common/Android.bp
index 209955d..47a2f21 100644
--- a/libs/binder_common/Android.bp
+++ b/libs/binder_common/Android.bp
@@ -10,7 +10,6 @@
rustlibs: [
"libbinder_rs",
"libbinder_rpc_unstable_bindgen",
- "liblazy_static",
],
apex_available: [
"com.android.compos",
diff --git a/libs/binder_common/lazy_service.rs b/libs/binder_common/lazy_service.rs
deleted file mode 100644
index 9d605b6..0000000
--- a/libs/binder_common/lazy_service.rs
+++ /dev/null
@@ -1,77 +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.
- */
-
-//! Rust API for lazy (aka dynamic) AIDL services.
-//! See https://source.android.com/devices/architecture/aidl/dynamic-aidl.
-
-use binder::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/libs/binder_common/lib.rs b/libs/binder_common/lib.rs
index fd81da5..14dd9f2 100644
--- a/libs/binder_common/lib.rs
+++ b/libs/binder_common/lib.rs
@@ -16,27 +16,5 @@
//! Common items useful for binder clients and/or servers.
-pub mod lazy_service;
pub mod rpc_client;
pub mod rpc_server;
-
-use binder::{ExceptionCode, Status};
-use std::ffi::CString;
-
-/// Constructs a new Binder error `Status` with the given `ExceptionCode` and message.
-pub fn new_binder_exception<T: AsRef<str>>(exception: ExceptionCode, message: T) -> Status {
- match exception {
- ExceptionCode::SERVICE_SPECIFIC => new_binder_service_specific_error(-1, message),
- _ => Status::new_exception(exception, to_cstring(message).as_deref()),
- }
-}
-
-/// Constructs a Binder `Status` representing a service-specific exception with the given code and
-/// message.
-pub fn new_binder_service_specific_error<T: AsRef<str>>(code: i32, message: T) -> Status {
- Status::new_service_specific_error(code, to_cstring(message).as_deref())
-}
-
-fn to_cstring<T: AsRef<str>>(message: T) -> Option<CString> {
- CString::new(message.as_ref()).ok()
-}
diff --git a/rialto/tests/test.rs b/rialto/tests/test.rs
index b6ccd9e..fb6a1ad 100644
--- a/rialto/tests/test.rs
+++ b/rialto/tests/test.rs
@@ -66,7 +66,7 @@
platformVersion: "~1.0".to_string(),
taskProfiles: vec![],
});
- let vm = VmInstance::create(service.as_ref(), &config, Some(console), Some(log))
+ let vm = VmInstance::create(service.as_ref(), &config, Some(console), Some(log), None)
.context("Failed to create VM")?;
vm.start().context("Failed to start VM")?;
diff --git a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
index 90aac1e..f6e9a71 100644
--- a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
+++ b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
@@ -122,6 +122,7 @@
final int trialCount = 10;
+ List<Double> vmStartingTimeMetrics = new ArrayList<>();
List<Double> bootTimeMetrics = new ArrayList<>();
List<Double> bootloaderTimeMetrics = new ArrayList<>();
List<Double> kernelBootTimeMetrics = new ArrayList<>();
@@ -139,13 +140,15 @@
BootResult result = tryBootVm(TAG, "test_vm_boot_time");
assertThat(result.payloadStarted).isTrue();
- final Double nanoToMilli = 1000000.0;
+ final double nanoToMilli = 1000000.0;
+ vmStartingTimeMetrics.add(result.getVMStartingElapsedNanoTime() / nanoToMilli);
bootTimeMetrics.add(result.endToEndNanoTime / nanoToMilli);
bootloaderTimeMetrics.add(result.getBootloaderElapsedNanoTime() / nanoToMilli);
kernelBootTimeMetrics.add(result.getKernelElapsedNanoTime() / nanoToMilli);
userspaceBootTimeMetrics.add(result.getUserspaceElapsedNanoTime() / nanoToMilli);
}
+ reportMetrics(vmStartingTimeMetrics, "avf_perf/microdroid/vm_starting_time_", "_ms");
reportMetrics(bootTimeMetrics, "avf_perf/microdroid/boot_time_", "_ms");
reportMetrics(bootloaderTimeMetrics, "avf_perf/microdroid/bootloader_time_", "_ms");
reportMetrics(kernelBootTimeMetrics, "avf_perf/microdroid/kernel_boot_time_", "_ms");
diff --git a/tests/helper/src/java/com/android/microdroid/test/MicrodroidDeviceTestBase.java b/tests/helper/src/java/com/android/microdroid/test/MicrodroidDeviceTestBase.java
index 84e189a..efd7c85 100644
--- a/tests/helper/src/java/com/android/microdroid/test/MicrodroidDeviceTestBase.java
+++ b/tests/helper/src/java/com/android/microdroid/test/MicrodroidDeviceTestBase.java
@@ -234,6 +234,7 @@
public static class BootResult {
public final boolean payloadStarted;
public final int deathReason;
+ public final long apiCallNanoTime;
public final long endToEndNanoTime;
public final OptionalLong vcpuStartedNanoTime;
@@ -243,11 +244,13 @@
BootResult(boolean payloadStarted,
int deathReason,
+ long apiCallNanoTime,
long endToEndNanoTime,
OptionalLong vcpuStartedNanoTime,
OptionalLong kernelStartedNanoTime,
OptionalLong initStartedNanoTime,
OptionalLong payloadStartedNanoTime) {
+ this.apiCallNanoTime = apiCallNanoTime;
this.payloadStarted = payloadStarted;
this.deathReason = deathReason;
this.endToEndNanoTime = endToEndNanoTime;
@@ -273,6 +276,10 @@
return payloadStartedNanoTime.getAsLong();
}
+ public long getVMStartingElapsedNanoTime() {
+ return getVcpuStartedNanoTime() - apiCallNanoTime;
+ }
+
public long getBootloaderElapsedNanoTime() {
return getKernelStartedNanoTime() - getVcpuStartedNanoTime();
}
@@ -307,12 +314,13 @@
super.onDied(vm, reason);
}
};
- long beginTime = System.nanoTime();
+ long apiCallNanoTime = System.nanoTime();
listener.runToFinish(logTag, vm);
return new BootResult(
payloadStarted.getNow(false),
deathReason.getNow(DeathReason.INFRASTRUCTURE_ERROR),
- endTime.getNow(beginTime) - beginTime,
+ apiCallNanoTime,
+ endTime.getNow(apiCallNanoTime) - apiCallNanoTime,
listener.getVcpuStartedNanoTime(),
listener.getKernelStartedNanoTime(),
listener.getInitStartedNanoTime(),
diff --git a/tests/hostside/Android.bp b/tests/hostside/Android.bp
index b7f34e7..5ce19bd 100644
--- a/tests/hostside/Android.bp
+++ b/tests/hostside/Android.bp
@@ -14,6 +14,7 @@
],
static_libs: [
"MicrodroidHostTestHelper",
+ "compatibility-host-util",
],
per_testcase_directory: true,
data: [
diff --git a/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java b/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java
index 07b8679..722ec74 100644
--- a/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java
+++ b/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java
@@ -31,6 +31,7 @@
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
+import com.android.compatibility.common.util.CddTest;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.result.TestDescription;
import com.android.tradefed.result.TestResult;
@@ -103,6 +104,11 @@
}
@Test
+ @CddTest(requirements = {
+ "9.17/C-1-1",
+ "9.17/C-1-2",
+ "9.17/C-1-4"
+ })
public void testCreateVmRequiresPermission() throws Exception {
// Revoke the MANAGE_VIRTUAL_MACHINE permission for the test app
CommandRunner android = new CommandRunner(getDevice());
@@ -330,6 +336,11 @@
}
@Test
+ @CddTest(requirements = {
+ "9.17/C-2-1",
+ "9.17/C-2-2",
+ "9.17/C-2-6"
+ })
public void testBootFailsWhenProtectedVmStartsWithImagesSignedWithDifferentKey()
throws Exception {
assumeTrue(isProtectedVmSupported());
@@ -345,6 +356,10 @@
}
@Test
+ @CddTest(requirements = {
+ "9.17/C-2-2",
+ "9.17/C-2-6"
+ })
public void testBootSucceedsWhenNonProtectedVmStartsWithImagesSignedWithDifferentKey()
throws Exception {
File key = findTestFile("test.com.android.virt.pem");
@@ -360,6 +375,10 @@
}
@Test
+ @CddTest(requirements = {
+ "9.17/C-2-2",
+ "9.17/C-2-6"
+ })
public void testBootFailsWhenBootloaderAndVbMetaAreSignedWithDifferentKeys()
throws Exception {
// Sign everything with key1 except vbmeta
@@ -380,6 +399,10 @@
}
@Test
+ @CddTest(requirements = {
+ "9.17/C-2-2",
+ "9.17/C-2-6"
+ })
public void testBootSucceedsWhenBootloaderAndVbmetaHaveSameSigningKeys()
throws Exception {
// Sign everything with key1 except bootloader and vbmeta
@@ -441,6 +464,11 @@
}
@Test
+ @CddTest(requirements = {
+ "9.17/C-1-1",
+ "9.17/C-1-2",
+ "9.17/C/1-3"
+ })
public void testMicrodroidBoots() throws Exception {
final String configPath = "assets/vm_config.json"; // path inside the APK
final String cid =
diff --git a/tests/testapk/Android.bp b/tests/testapk/Android.bp
index d468d76..29a74ca 100644
--- a/tests/testapk/Android.bp
+++ b/tests/testapk/Android.bp
@@ -17,6 +17,7 @@
"cbor-java",
"com.android.microdroid.testservice-java",
"truth-prebuilt",
+ "compatibility-common-util-devicesidelib",
],
libs: ["android.system.virtualmachine"],
jni_libs: ["MicrodroidTestNativeLib"],
diff --git a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
index b429e4d..db2ca0f 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -30,6 +30,7 @@
import android.system.virtualmachine.VirtualMachineException;
import android.util.Log;
+import com.android.compatibility.common.util.CddTest;
import com.android.microdroid.testservice.ITestService;
import org.junit.Before;
@@ -80,6 +81,10 @@
private static final int MIN_MEM_X86_64 = 196;
@Test
+ @CddTest(requirements = {
+ "9.17/C-1-1",
+ "9.17/C-2-1"
+ })
public void connectToVmService() throws VirtualMachineException, InterruptedException {
assume()
.withMessage("SKip on 5.4 kernel. b/218303240")
@@ -177,6 +182,10 @@
}
@Test
+ @CddTest(requirements = {
+ "9.17/C-1-1",
+ "9.17/C-2-7"
+ })
public void changingDebugLevelInvalidatesVmIdentity()
throws VirtualMachineException, InterruptedException, IOException {
assume()
@@ -252,6 +261,10 @@
}
@Test
+ @CddTest(requirements = {
+ "9.17/C-1-1",
+ "9.17/C-2-7"
+ })
public void instancesOfSameVmHaveDifferentCdis()
throws VirtualMachineException, InterruptedException {
assume()
@@ -276,6 +289,10 @@
}
@Test
+ @CddTest(requirements = {
+ "9.17/C-1-1",
+ "9.17/C-2-7"
+ })
public void sameInstanceKeepsSameCdis()
throws VirtualMachineException, InterruptedException {
assume()
@@ -297,6 +314,10 @@
}
@Test
+ @CddTest(requirements = {
+ "9.17/C-1-1",
+ "9.17/C-2-7"
+ })
public void bccIsSuperficiallyWellFormed()
throws VirtualMachineException, InterruptedException, CborException {
assume()
@@ -417,12 +438,20 @@
}
@Test
+ @CddTest(requirements = {
+ "9.17/C-1-1",
+ "9.17/C-2-7"
+ })
public void bootFailsWhenMicrodroidDataIsCompromised()
throws VirtualMachineException, InterruptedException, IOException {
assertThatBootFailsAfterCompromisingPartition(MICRODROID_PARTITION_UUID);
}
@Test
+ @CddTest(requirements = {
+ "9.17/C-1-1",
+ "9.17/C-2-7"
+ })
public void bootFailsWhenUBootAvbDataIsCompromised()
throws VirtualMachineException, InterruptedException, IOException {
if (mProtectedVm) {
@@ -434,6 +463,10 @@
}
@Test
+ @CddTest(requirements = {
+ "9.17/C-1-1",
+ "9.17/C-2-7"
+ })
public void bootFailsWhenUBootEnvDataIsCompromised()
throws VirtualMachineException, InterruptedException, IOException {
if (mProtectedVm) {
@@ -445,6 +478,10 @@
}
@Test
+ @CddTest(requirements = {
+ "9.17/C-1-1",
+ "9.17/C-2-7"
+ })
public void bootFailsWhenPvmFwDataIsCompromised()
throws VirtualMachineException, InterruptedException, IOException {
if (mProtectedVm) {
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index cc8d8a3..bba75ac 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -34,9 +34,9 @@
VirtualMachineRawConfig::VirtualMachineRawConfig,
VirtualMachineState::VirtualMachineState,
};
-use android_system_virtualizationservice::binder::{
- self, BinderFeatures, ExceptionCode, Interface, ParcelFileDescriptor, SpIBinder, Status,
- StatusCode, Strong, ThreadState,
+use binder::{
+ self, BinderFeatures, ExceptionCode, Interface, LazyServiceGuard, ParcelFileDescriptor,
+ SpIBinder, Status, StatusCode, Strong, ThreadState,
};
use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::{
IVirtualMachineService::{
@@ -45,7 +45,7 @@
},
};
use anyhow::{anyhow, bail, Context, Result};
-use binder_common::{lazy_service::LazyServiceGuard, new_binder_exception, rpc_server::run_rpc_server_with_factory};
+use binder_common::rpc_server::run_rpc_server_with_factory;
use disk::QcowFile;
use idsig::{HashAlgorithm, V4Signature};
use log::{debug, error, info, warn, trace};
@@ -160,23 +160,23 @@
) -> binder::Result<()> {
check_manage_access()?;
let size = size.try_into().map_err(|e| {
- new_binder_exception(
+ Status::new_exception_str(
ExceptionCode::ILLEGAL_ARGUMENT,
- format!("Invalid size {}: {}", size, e),
+ Some(format!("Invalid size {}: {}", size, e)),
)
})?;
let image = clone_file(image_fd)?;
// initialize the file. Any data in the file will be erased.
image.set_len(0).map_err(|e| {
- new_binder_exception(
- ExceptionCode::SERVICE_SPECIFIC,
- format!("Failed to reset a file: {}", e),
+ Status::new_service_specific_error_str(
+ -1,
+ Some(format!("Failed to reset a file: {}", e)),
)
})?;
let mut part = QcowFile::new(image, size).map_err(|e| {
- new_binder_exception(
- ExceptionCode::SERVICE_SPECIFIC,
- format!("Failed to create QCOW2 image: {}", e),
+ Status::new_service_specific_error_str(
+ -1,
+ Some(format!("Failed to create QCOW2 image: {}", e)),
)
})?;
@@ -189,9 +189,9 @@
)),
}
.map_err(|e| {
- new_binder_exception(
- ExceptionCode::SERVICE_SPECIFIC,
- format!("Failed to initialize partition as {:?}: {}", partition_type, e),
+ Status::new_service_specific_error_str(
+ -1,
+ Some(format!("Failed to initialize partition as {:?}: {}", partition_type, e)),
)
})?;
@@ -379,12 +379,12 @@
"Failed to create temporary directory {:?} for VM files: {:?}",
temporary_directory, e
);
- new_binder_exception(
- ExceptionCode::SERVICE_SPECIFIC,
- format!(
+ Status::new_service_specific_error_str(
+ -1,
+ Some(format!(
"Failed to create temporary directory {:?} for VM files: {}",
temporary_directory, e
- ),
+ )),
)
})?;
@@ -395,9 +395,12 @@
load_app_config(config, &temporary_directory).map_err(|e| {
error!("Failed to load app config from {}: {:?}", &config.configPath, e);
*is_protected = config.protectedVm;
- new_binder_exception(
- ExceptionCode::SERVICE_SPECIFIC,
- format!("Failed to load app config from {}: {}", &config.configPath, e),
+ Status::new_service_specific_error_str(
+ -1,
+ Some(format!(
+ "Failed to load app config from {}: {}",
+ &config.configPath, e
+ )),
)
})?,
),
@@ -423,14 +426,14 @@
}
})
.try_for_each(check_label_for_partition)
- .map_err(|e| new_binder_exception(ExceptionCode::SERVICE_SPECIFIC, e.to_string()))?;
+ .map_err(|e| Status::new_service_specific_error_str(-1, Some(e.to_string())))?;
let zero_filler_path = temporary_directory.join("zero.img");
write_zero_filler(&zero_filler_path).map_err(|e| {
error!("Failed to make composite image: {:?}", e);
- new_binder_exception(
- ExceptionCode::SERVICE_SPECIFIC,
- format!("Failed to make composite image: {}", e),
+ Status::new_service_specific_error_str(
+ -1,
+ Some(format!("Failed to make composite image: {}", e)),
)
})?;
@@ -456,9 +459,9 @@
let ramdump_path = temporary_directory.join("ramdump");
let ramdump = prepare_ramdump_file(&ramdump_path).map_err(|e| {
error!("Failed to prepare ramdump file: {}", e);
- new_binder_exception(
- ExceptionCode::SERVICE_SPECIFIC,
- format!("Failed to prepare ramdump file: {}", e),
+ Status::new_service_specific_error_str(
+ -1,
+ Some(format!("Failed to prepare ramdump file: {}", e)),
)
})?;
@@ -492,9 +495,9 @@
)
.map_err(|e| {
error!("Failed to create VM with config {:?}: {:?}", config, e);
- new_binder_exception(
- ExceptionCode::SERVICE_SPECIFIC,
- format!("Failed to create VM: {}", e),
+ Status::new_service_specific_error_str(
+ -1,
+ Some(format!("Failed to create VM: {}", e)),
)
})?,
);
@@ -575,9 +578,9 @@
let image = if !disk.partitions.is_empty() {
if disk.image.is_some() {
warn!("DiskImage {:?} contains both image and partitions.", disk);
- return Err(new_binder_exception(
+ return Err(Status::new_exception_str(
ExceptionCode::ILLEGAL_ARGUMENT,
- "DiskImage contains both image and partitions.",
+ Some("DiskImage contains both image and partitions."),
));
}
@@ -592,9 +595,9 @@
)
.map_err(|e| {
error!("Failed to make composite image with config {:?}: {:?}", disk, e);
- new_binder_exception(
- ExceptionCode::SERVICE_SPECIFIC,
- format!("Failed to make composite image: {}", e),
+ Status::new_service_specific_error_str(
+ -1,
+ Some(format!("Failed to make composite image: {}", e)),
)
})?;
@@ -607,9 +610,9 @@
clone_file(image)?
} else {
warn!("DiskImage {:?} didn't contain image or partitions.", disk);
- return Err(new_binder_exception(
+ return Err(Status::new_exception_str(
ExceptionCode::ILLEGAL_ARGUMENT,
- "DiskImage didn't contain image or partitions.",
+ Some("DiskImage didn't contain image or partitions."),
));
};
@@ -700,15 +703,15 @@
Ok(sid) => Ok(sid.to_owned()),
Err(e) => {
error!("SID was not valid UTF-8: {}", e);
- Err(new_binder_exception(
+ Err(Status::new_exception_str(
ExceptionCode::ILLEGAL_ARGUMENT,
- format!("SID was not valid UTF-8: {}", e),
+ Some(format!("SID was not valid UTF-8: {}", e)),
))
}
}
} else {
error!("Missing SID on createVm");
- Err(new_binder_exception(ExceptionCode::SECURITY, "Missing SID on createVm"))
+ Err(Status::new_exception_str(ExceptionCode::SECURITY, Some("Missing SID on createVm")))
}
})
}
@@ -726,9 +729,9 @@
if perm_svc.checkPermission(perm, calling_pid, calling_uid as i32)? {
Ok(())
} else {
- Err(new_binder_exception(
+ Err(Status::new_exception_str(
ExceptionCode::SECURITY,
- format!("does not have the {} permission", perm),
+ Some(format!("does not have the {} permission", perm)),
))
}
}
@@ -804,26 +807,26 @@
fn start(&self) -> binder::Result<()> {
self.instance.start().map_err(|e| {
error!("Error starting VM with CID {}: {:?}", self.instance.cid, e);
- new_binder_exception(ExceptionCode::SERVICE_SPECIFIC, e.to_string())
+ Status::new_service_specific_error_str(-1, Some(e.to_string()))
})
}
fn stop(&self) -> binder::Result<()> {
self.instance.kill().map_err(|e| {
error!("Error stopping VM with CID {}: {:?}", self.instance.cid, e);
- new_binder_exception(ExceptionCode::SERVICE_SPECIFIC, e.to_string())
+ Status::new_service_specific_error_str(-1, Some(e.to_string()))
})
}
fn connectVsock(&self, port: i32) -> binder::Result<ParcelFileDescriptor> {
if !matches!(&*self.instance.vm_state.lock().unwrap(), VmState::Running { .. }) {
- return Err(new_binder_exception(ExceptionCode::SERVICE_SPECIFIC, "VM is not running"));
+ return Err(Status::new_service_specific_error_str(-1, Some("VM is not running")));
}
let stream =
VsockStream::connect_with_cid_port(self.instance.cid, port as u32).map_err(|e| {
- new_binder_exception(
- ExceptionCode::SERVICE_SPECIFIC,
- format!("Failed to connect: {}", e),
+ Status::new_service_specific_error_str(
+ -1,
+ Some(format!("Failed to connect: {}", e)),
)
})?;
Ok(vsock_stream_to_pfd(stream))
@@ -1002,9 +1005,9 @@
/// Converts a `&ParcelFileDescriptor` to a `File` by cloning the file.
fn clone_file(file: &ParcelFileDescriptor) -> Result<File, Status> {
file.as_ref().try_clone().map_err(|e| {
- new_binder_exception(
+ Status::new_exception_str(
ExceptionCode::BAD_PARCELABLE,
- format!("Failed to clone File from ParcelFileDescriptor: {}", e),
+ Some(format!("Failed to clone File from ParcelFileDescriptor: {}", e)),
)
})
}
@@ -1024,9 +1027,9 @@
/// Parses the platform version requirement string.
fn parse_platform_version_req(s: &str) -> Result<VersionReq, Status> {
VersionReq::parse(s).map_err(|e| {
- new_binder_exception(
+ Status::new_exception_str(
ExceptionCode::BAD_PARCELABLE,
- format!("Invalid platform version requirement {}: {}", s, e),
+ Some(format!("Invalid platform version requirement {}: {}", s, e)),
)
})
}
@@ -1061,16 +1064,17 @@
let cid = self.cid;
if let Some(vm) = self.state.lock().unwrap().get_vm(cid) {
info!("VM having CID {} started payload", cid);
- vm.update_payload_state(PayloadState::Started)
- .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))?;
+ vm.update_payload_state(PayloadState::Started).map_err(|e| {
+ Status::new_exception_str(ExceptionCode::ILLEGAL_STATE, Some(e.to_string()))
+ })?;
let stream = vm.stream.lock().unwrap().take();
vm.callbacks.notify_payload_started(cid, stream);
Ok(())
} else {
error!("notifyPayloadStarted is called from an unknown CID {}", cid);
- Err(new_binder_exception(
- ExceptionCode::SERVICE_SPECIFIC,
- format!("cannot find a VM with CID {}", cid),
+ Err(Status::new_service_specific_error_str(
+ -1,
+ Some(format!("cannot find a VM with CID {}", cid)),
))
}
}
@@ -1079,15 +1083,16 @@
let cid = self.cid;
if let Some(vm) = self.state.lock().unwrap().get_vm(cid) {
info!("VM having CID {} payload is ready", cid);
- vm.update_payload_state(PayloadState::Ready)
- .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))?;
+ vm.update_payload_state(PayloadState::Ready).map_err(|e| {
+ Status::new_exception_str(ExceptionCode::ILLEGAL_STATE, Some(e.to_string()))
+ })?;
vm.callbacks.notify_payload_ready(cid);
Ok(())
} else {
error!("notifyPayloadReady is called from an unknown CID {}", cid);
- Err(new_binder_exception(
- ExceptionCode::SERVICE_SPECIFIC,
- format!("cannot find a VM with CID {}", cid),
+ Err(Status::new_service_specific_error_str(
+ -1,
+ Some(format!("cannot find a VM with CID {}", cid)),
))
}
}
@@ -1096,15 +1101,16 @@
let cid = self.cid;
if let Some(vm) = self.state.lock().unwrap().get_vm(cid) {
info!("VM having CID {} finished payload", cid);
- vm.update_payload_state(PayloadState::Finished)
- .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))?;
+ vm.update_payload_state(PayloadState::Finished).map_err(|e| {
+ Status::new_exception_str(ExceptionCode::ILLEGAL_STATE, Some(e.to_string()))
+ })?;
vm.callbacks.notify_payload_finished(cid, exit_code);
Ok(())
} else {
error!("notifyPayloadFinished is called from an unknown CID {}", cid);
- Err(new_binder_exception(
- ExceptionCode::SERVICE_SPECIFIC,
- format!("cannot find a VM with CID {}", cid),
+ Err(Status::new_service_specific_error_str(
+ -1,
+ Some(format!("cannot find a VM with CID {}", cid)),
))
}
}
@@ -1113,15 +1119,16 @@
let cid = self.cid;
if let Some(vm) = self.state.lock().unwrap().get_vm(cid) {
info!("VM having CID {} encountered an error", cid);
- vm.update_payload_state(PayloadState::Finished)
- .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))?;
+ vm.update_payload_state(PayloadState::Finished).map_err(|e| {
+ Status::new_exception_str(ExceptionCode::ILLEGAL_STATE, Some(e.to_string()))
+ })?;
vm.callbacks.notify_error(cid, error_code, message);
Ok(())
} else {
error!("notifyError is called from an unknown CID {}", cid);
- Err(new_binder_exception(
- ExceptionCode::SERVICE_SPECIFIC,
- format!("cannot find a VM with CID {}", cid),
+ Err(Status::new_service_specific_error_str(
+ -1,
+ Some(format!("cannot find a VM with CID {}", cid)),
))
}
}
diff --git a/virtualizationservice/src/crosvm.rs b/virtualizationservice/src/crosvm.rs
index 95c5c53..3e1a151 100644
--- a/virtualizationservice/src/crosvm.rs
+++ b/virtualizationservice/src/crosvm.rs
@@ -36,7 +36,7 @@
use std::thread;
use vsock::VsockStream;
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::DeathReason::DeathReason;
-use android_system_virtualmachineservice::binder::Strong;
+use binder::Strong;
use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::IVirtualMachineService;
const CROSVM_PATH: &str = "/apex/com.android.virt/bin/crosvm";
diff --git a/virtualizationservice/src/main.rs b/virtualizationservice/src/main.rs
index 7bfb531..3b0adb9 100644
--- a/virtualizationservice/src/main.rs
+++ b/virtualizationservice/src/main.rs
@@ -22,7 +22,7 @@
use crate::aidl::{VirtualizationService, BINDER_SERVICE_IDENTIFIER, TEMPORARY_DIRECTORY};
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualizationService::BnVirtualizationService;
-use android_system_virtualizationservice::binder::{register_lazy_service, BinderFeatures, ProcessState};
+use binder::{register_lazy_service, BinderFeatures, ProcessState};
use anyhow::Error;
use log::{info, Level};
use std::fs::{remove_dir_all, remove_file, read_dir};
diff --git a/virtualizationservice/src/payload.rs b/virtualizationservice/src/payload.rs
index c0153b9..42c51a1 100644
--- a/virtualizationservice/src/payload.rs
+++ b/virtualizationservice/src/payload.rs
@@ -19,9 +19,8 @@
VirtualMachineAppConfig::VirtualMachineAppConfig,
VirtualMachineRawConfig::VirtualMachineRawConfig,
};
-use android_system_virtualizationservice::binder::ParcelFileDescriptor;
use anyhow::{anyhow, bail, Context, Result};
-use binder::wait_for_interface;
+use binder::{wait_for_interface, ParcelFileDescriptor};
use log::{info, warn};
use microdroid_metadata::{ApexPayload, ApkPayload, Metadata};
use microdroid_payload_config::{ApexConfig, VmPayloadConfig};
diff --git a/vm/Android.bp b/vm/Android.bp
index 2b83ca7..f9eac4d 100644
--- a/vm/Android.bp
+++ b/vm/Android.bp
@@ -11,6 +11,7 @@
rustlibs: [
"android.system.virtualizationservice-rust",
"libanyhow",
+ "libbinder_rs",
"libenv_logger",
"liblibc",
"liblog_rust",
diff --git a/vm/src/create_idsig.rs b/vm/src/create_idsig.rs
index fe7cd82..9a66228 100644
--- a/vm/src/create_idsig.rs
+++ b/vm/src/create_idsig.rs
@@ -15,7 +15,7 @@
//! Command to create or update an idsig for APK
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualizationService::IVirtualizationService;
-use android_system_virtualizationservice::binder::ParcelFileDescriptor;
+use binder::ParcelFileDescriptor;
use anyhow::{Context, Error};
use std::fs::{File, OpenOptions};
use std::path::Path;
diff --git a/vm/src/create_partition.rs b/vm/src/create_partition.rs
index 049c201..affa28e 100644
--- a/vm/src/create_partition.rs
+++ b/vm/src/create_partition.rs
@@ -16,7 +16,7 @@
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualizationService::IVirtualizationService;
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::PartitionType::PartitionType;
-use android_system_virtualizationservice::binder::ParcelFileDescriptor;
+use binder::ParcelFileDescriptor;
use anyhow::{Context, Error};
use std::convert::TryInto;
use std::fs::OpenOptions;
diff --git a/vm/src/main.rs b/vm/src/main.rs
index 60786ac..c421b04 100644
--- a/vm/src/main.rs
+++ b/vm/src/main.rs
@@ -22,8 +22,8 @@
IVirtualizationService::IVirtualizationService, PartitionType::PartitionType,
VirtualMachineAppConfig::DebugLevel::DebugLevel,
};
-use android_system_virtualizationservice::binder::ProcessState;
use anyhow::{Context, Error};
+use binder::ProcessState;
use create_idsig::command_create_idsig;
use create_partition::command_create_partition;
use run::{command_run, command_run_app};
diff --git a/vm/src/run.rs b/vm/src/run.rs
index 44eb27a..9bd7863 100644
--- a/vm/src/run.rs
+++ b/vm/src/run.rs
@@ -16,19 +16,13 @@
use crate::create_partition::command_create_partition;
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
- DeathReason::DeathReason,
- IVirtualMachineCallback::{BnVirtualMachineCallback, IVirtualMachineCallback},
- IVirtualizationService::IVirtualizationService,
- PartitionType::PartitionType,
+ IVirtualizationService::IVirtualizationService, PartitionType::PartitionType,
VirtualMachineAppConfig::DebugLevel::DebugLevel,
- VirtualMachineAppConfig::VirtualMachineAppConfig,
- VirtualMachineConfig::VirtualMachineConfig,
+ VirtualMachineAppConfig::VirtualMachineAppConfig, VirtualMachineConfig::VirtualMachineConfig,
VirtualMachineState::VirtualMachineState,
};
-use android_system_virtualizationservice::binder::{
- BinderFeatures, Interface, ParcelFileDescriptor, Result as BinderResult,
-};
use anyhow::{bail, Context, Error};
+use binder::ParcelFileDescriptor;
use microdroid_payload_config::VmPayloadConfig;
use std::fs::File;
use std::io::{self, BufRead, BufReader};
@@ -197,10 +191,9 @@
Some(duplicate_stdout()?)
};
- let vm = VmInstance::create(service, config, console, log).context("Failed to create VM")?;
- let callback =
- BnVirtualMachineCallback::new_binder(VirtualMachineCallback {}, BinderFeatures::default());
- vm.vm.registerCallback(&callback)?;
+ let callback = Box::new(Callback {});
+ let vm = VmInstance::create(service, config, console, log, Some(callback))
+ .context("Failed to create VM")?;
vm.start().context("Failed to start VM")?;
println!(
@@ -246,20 +239,13 @@
Ok(config.extra_apks.into_iter().map(|x| x.path).collect())
}
-#[derive(Debug)]
-struct VirtualMachineCallback {}
+struct Callback {}
-impl Interface for VirtualMachineCallback {}
-
-impl IVirtualMachineCallback for VirtualMachineCallback {
- fn onPayloadStarted(
- &self,
- _cid: i32,
- stream: Option<&ParcelFileDescriptor>,
- ) -> BinderResult<()> {
+impl vmclient::VmCallback for Callback {
+ fn on_payload_started(&self, _cid: i32, stream: Option<&File>) {
// Show the output of the payload
if let Some(stream) = stream {
- let mut reader = BufReader::new(stream.as_ref());
+ let mut reader = BufReader::new(stream);
loop {
let mut s = String::new();
match reader.read_line(&mut s) {
@@ -269,31 +255,18 @@
};
}
}
- Ok(())
}
- fn onPayloadReady(&self, _cid: i32) -> BinderResult<()> {
+ fn on_payload_ready(&self, _cid: i32) {
eprintln!("payload is ready");
- Ok(())
}
- fn onPayloadFinished(&self, _cid: i32, exit_code: i32) -> BinderResult<()> {
+ fn on_payload_finished(&self, _cid: i32, exit_code: i32) {
eprintln!("payload finished with exit code {}", exit_code);
- Ok(())
}
- fn onError(&self, _cid: i32, error_code: i32, message: &str) -> BinderResult<()> {
+ fn on_error(&self, _cid: i32, error_code: i32, message: &str) {
eprintln!("VM encountered an error: code={}, message={}", error_code, message);
- Ok(())
- }
-
- fn onRamdump(&self, _cid: i32, _stream: &ParcelFileDescriptor) -> BinderResult<()> {
- // Do nothing. We get ramdump from the vmclient library.
- Ok(())
- }
-
- fn onDied(&self, _cid: i32, _reason: DeathReason) -> BinderResult<()> {
- Ok(())
}
}
diff --git a/vmbase/example/tests/test.rs b/vmbase/example/tests/test.rs
index 4928846..fd6eb8c 100644
--- a/vmbase/example/tests/test.rs
+++ b/vmbase/example/tests/test.rs
@@ -63,7 +63,7 @@
});
let console = duplicate_stdout()?;
let log = duplicate_stdout()?;
- let vm = VmInstance::create(service.as_ref(), &config, Some(console), Some(log))
+ let vm = VmInstance::create(service.as_ref(), &config, Some(console), Some(log), None)
.context("Failed to create VM")?;
vm.start().context("Failed to start VM")?;
info!("Started example VM.");
diff --git a/vmclient/src/lib.rs b/vmclient/src/lib.rs
index b3bb635..129e6c3 100644
--- a/vmclient/src/lib.rs
+++ b/vmclient/src/lib.rs
@@ -64,6 +64,32 @@
_death_recipient: DeathRecipient,
}
+/// A trait to be implemented by clients to handle notification of significant changes to the VM
+/// state. Default implementations of all functions are provided so clients only need to handle the
+/// notifications they are interested in.
+#[allow(unused_variables)]
+pub trait VmCallback {
+ /// Called when the payload has been started within the VM. If present, `stream` is connected
+ /// to the stdin/stdout of the payload.
+ fn on_payload_started(&self, cid: i32, stream: Option<&File>) {}
+
+ /// Callend when the payload has notified Virtualization Service that it is ready to serve
+ /// clients.
+ fn on_payload_ready(&self, cid: i32) {}
+
+ /// Called when the payload has exited in the VM. `exit_code` is the exit code of the payload
+ /// process.
+ fn on_payload_finished(&self, cid: i32, exit_code: i32) {}
+
+ /// Called when an error has occurred in the VM. The `error_code` and `message` may give
+ /// further details.
+ fn on_error(&self, cid: i32, error_code: i32, message: &str) {}
+
+ /// Called when the VM has exited, all resources have been freed, and any logs have been
+ /// written. `death_reason` gives an indication why the VM exited.
+ fn on_died(&self, cid: i32, death_reason: DeathReason) {}
+}
+
impl VmInstance {
/// Creates (but doesn't start) a new VM with the given configuration.
pub fn create(
@@ -71,6 +97,7 @@
config: &VirtualMachineConfig,
console: Option<File>,
log: Option<File>,
+ callback: Option<Box<dyn VmCallback + Send + Sync>>,
) -> BinderResult<Self> {
let console = console.map(ParcelFileDescriptor::new);
let log = log.map(ParcelFileDescriptor::new);
@@ -82,7 +109,7 @@
// Register callback before starting VM, in case it dies immediately.
let state = Arc::new(Monitor::new(VmState::default()));
let callback = BnVirtualMachineCallback::new_binder(
- VirtualMachineCallback { state: state.clone() },
+ VirtualMachineCallback { state: state.clone(), client_callback: callback },
BinderFeatures::default(),
);
vm.registerCallback(&callback)?;
@@ -219,9 +246,21 @@
}
}
-#[derive(Debug)]
struct VirtualMachineCallback {
state: Arc<Monitor<VmState>>,
+ client_callback: Option<Box<dyn VmCallback + Send + Sync>>,
+}
+
+impl Debug for VirtualMachineCallback {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("VirtualMachineCallback")
+ .field("state", &self.state)
+ .field(
+ "client_callback",
+ &if self.client_callback.is_some() { "Some(...)" } else { "None" },
+ )
+ .finish()
+ }
}
impl Interface for VirtualMachineCallback {}
@@ -229,25 +268,37 @@
impl IVirtualMachineCallback for VirtualMachineCallback {
fn onPayloadStarted(
&self,
- _cid: i32,
- _stream: Option<&ParcelFileDescriptor>,
+ cid: i32,
+ stream: Option<&ParcelFileDescriptor>,
) -> BinderResult<()> {
self.state.notify_state(VirtualMachineState::STARTED);
+ if let Some(ref callback) = self.client_callback {
+ callback.on_payload_started(cid, stream.map(ParcelFileDescriptor::as_ref));
+ }
Ok(())
}
- fn onPayloadReady(&self, _cid: i32) -> BinderResult<()> {
+ fn onPayloadReady(&self, cid: i32) -> BinderResult<()> {
self.state.notify_state(VirtualMachineState::READY);
+ if let Some(ref callback) = self.client_callback {
+ callback.on_payload_ready(cid);
+ }
Ok(())
}
- fn onPayloadFinished(&self, _cid: i32, _exit_code: i32) -> BinderResult<()> {
+ fn onPayloadFinished(&self, cid: i32, exit_code: i32) -> BinderResult<()> {
self.state.notify_state(VirtualMachineState::FINISHED);
+ if let Some(ref callback) = self.client_callback {
+ callback.on_payload_finished(cid, exit_code);
+ }
Ok(())
}
- fn onError(&self, _cid: i32, _error_code: i32, _message: &str) -> BinderResult<()> {
+ fn onError(&self, cid: i32, error_code: i32, message: &str) -> BinderResult<()> {
self.state.notify_state(VirtualMachineState::FINISHED);
+ if let Some(ref callback) = self.client_callback {
+ callback.on_error(cid, error_code, message);
+ }
Ok(())
}
@@ -257,8 +308,12 @@
Ok(())
}
- fn onDied(&self, _cid: i32, reason: AidlDeathReason) -> BinderResult<()> {
- self.state.notify_death(reason.into());
+ fn onDied(&self, cid: i32, reason: AidlDeathReason) -> BinderResult<()> {
+ let reason = reason.into();
+ self.state.notify_death(reason);
+ if let Some(ref callback) = self.client_callback {
+ callback.on_died(cid, reason);
+ }
Ok(())
}
}