Make ErrorCode an enum
Change the VS AIDL to define it as an enum. Added a new common AIDL
module to hold it, since this is needed by both existing AIDLs, and we
don't want either directly depending on the other.
Modify vmclient to also have Rust enum for ErrorCode, with translation
logic, in the same way as we did for DeathReason. Switch to Debug
rather than Display for these enums.
Also fixed a couple of AIDL warnings (enum-explicit-default).
We also need translation in the Java API, but I'll do that as part of
https://r.android.com/2192077.
Bug: 236811123
Test: atest MicrodroidTests MicrodroidHostTestCases
Test: composd_cmd test-compile
Change-Id: I561e5f43f0f1c74d1318dc41782ed390bb5f0337
diff --git a/compos/common/compos_client.rs b/compos/common/compos_client.rs
index 946bc5b..d74a6f9 100644
--- a/compos/common/compos_client.rs
+++ b/compos/common/compos_client.rs
@@ -33,7 +33,7 @@
use std::num::NonZeroU32;
use std::path::{Path, PathBuf};
use std::thread;
-use vmclient::{DeathReason, VmInstance, VmWaitError};
+use vmclient::{DeathReason, ErrorCode, VmInstance, VmWaitError};
/// This owns an instance of the CompOS VM.
pub struct ComposClient(VmInstance);
@@ -241,8 +241,8 @@
log::warn!("VM payload finished, cid = {}, exit code = {}", cid, exit_code);
}
- fn on_error(&self, cid: i32, error_code: i32, message: &str) {
- log::warn!("VM error, cid = {}, error code = {}, message = {}", cid, error_code, message);
+ fn on_error(&self, cid: i32, error_code: ErrorCode, message: &str) {
+ log::warn!("VM error, cid = {}, error code = {:?}, message = {}", cid, error_code, message);
}
fn on_died(&self, cid: i32, death_reason: DeathReason) {
diff --git a/microdroid_manager/Android.bp b/microdroid_manager/Android.bp
index cfb851b..f3fa2f5 100644
--- a/microdroid_manager/Android.bp
+++ b/microdroid_manager/Android.bp
@@ -11,6 +11,7 @@
rustlibs: [
"android.hardware.security.dice-V1-rust",
"android.security.dice-rust",
+ "android.system.virtualizationcommon-rust",
"android.system.virtualizationservice-rust",
"android.system.virtualmachineservice-rust",
"libanyhow",
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 9e1890f..e3ad495 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -23,6 +23,10 @@
Config::Config, InputValues::InputValues, Mode::Mode,
};
use android_security_dice::aidl::android::security::dice::IDiceMaintenance::IDiceMaintenance;
+use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::ErrorCode::ErrorCode;
+use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::{
+ VM_BINDER_SERVICE_PORT, VM_STREAM_SERVICE_PORT, IVirtualMachineService,
+};
use anyhow::{anyhow, bail, ensure, Context, Error, Result};
use apkverify::{get_public_key_der, verify};
use binder::{wait_for_interface, Strong};
@@ -49,10 +53,6 @@
use std::time::{Duration, SystemTime};
use vsock::VsockStream;
-use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::{
- ERROR_PAYLOAD_CHANGED, ERROR_PAYLOAD_VERIFICATION_FAILED, ERROR_PAYLOAD_INVALID_CONFIG, ERROR_UNKNOWN, VM_BINDER_SERVICE_PORT, VM_STREAM_SERVICE_PORT, IVirtualMachineService,
-};
-
const WAIT_TIMEOUT: Duration = Duration::from_secs(10);
const MAIN_APK_PATH: &str = "/dev/block/by-name/microdroid-apk";
const MAIN_APK_IDSIG_PATH: &str = "/dev/block/by-name/microdroid-apk-idsig";
@@ -88,22 +88,24 @@
InvalidConfig(String),
}
-fn translate_error(err: &Error) -> (i32, String) {
+fn translate_error(err: &Error) -> (ErrorCode, String) {
if let Some(e) = err.downcast_ref::<MicrodroidError>() {
match e {
- MicrodroidError::PayloadChanged(msg) => (ERROR_PAYLOAD_CHANGED, msg.to_string()),
+ MicrodroidError::PayloadChanged(msg) => (ErrorCode::PAYLOAD_CHANGED, msg.to_string()),
MicrodroidError::PayloadVerificationFailed(msg) => {
- (ERROR_PAYLOAD_VERIFICATION_FAILED, msg.to_string())
+ (ErrorCode::PAYLOAD_VERIFICATION_FAILED, msg.to_string())
}
- MicrodroidError::InvalidConfig(msg) => (ERROR_PAYLOAD_INVALID_CONFIG, msg.to_string()),
+ MicrodroidError::InvalidConfig(msg) => {
+ (ErrorCode::PAYLOAD_CONFIG_INVALID, msg.to_string())
+ }
// Connection failure won't be reported to VS; return the default value
MicrodroidError::FailedToConnectToVirtualizationService(msg) => {
- (ERROR_UNKNOWN, msg.to_string())
+ (ErrorCode::UNKNOWN, msg.to_string())
}
}
} else {
- (ERROR_UNKNOWN, err.to_string())
+ (ErrorCode::UNKNOWN, err.to_string())
}
}
diff --git a/virtualizationservice/Android.bp b/virtualizationservice/Android.bp
index b6b7b09..1493cb8 100644
--- a/virtualizationservice/Android.bp
+++ b/virtualizationservice/Android.bp
@@ -20,6 +20,7 @@
},
prefer_rlib: true,
rustlibs: [
+ "android.system.virtualizationcommon-rust",
"android.system.virtualizationservice-rust",
"android.system.virtualmachineservice-rust",
"android.os.permissions_aidl-rust",
diff --git a/virtualizationservice/aidl/Android.bp b/virtualizationservice/aidl/Android.bp
index 30a4b03..4d5326a 100644
--- a/virtualizationservice/aidl/Android.bp
+++ b/virtualizationservice/aidl/Android.bp
@@ -5,6 +5,7 @@
aidl_interface {
name: "android.system.virtualizationservice",
srcs: ["android/system/virtualizationservice/**/*.aidl"],
+ imports: ["android.system.virtualizationcommon"],
// This is never accessed directly. Apps are expected to use this indirectly via the Java
// wrapper android.system.virtualmachine.
unstable: true,
@@ -35,6 +36,7 @@
aidl_interface {
name: "android.system.virtualmachineservice",
srcs: ["android/system/virtualmachineservice/**/*.aidl"],
+ imports: ["android.system.virtualizationcommon"],
unstable: true,
backend: {
rust: {
@@ -46,3 +48,27 @@
},
},
}
+
+aidl_interface {
+ name: "android.system.virtualizationcommon",
+ srcs: ["android/system/virtualizationcommon/**/*.aidl"],
+ unstable: true,
+ backend: {
+ java: {
+ apex_available: ["com.android.virt"],
+ },
+ ndk: {
+ apex_available: [
+ "com.android.virt",
+ "com.android.compos",
+ ],
+ },
+ rust: {
+ enabled: true,
+ apex_available: [
+ "com.android.virt",
+ "com.android.compos",
+ ],
+ },
+ },
+}
diff --git a/virtualizationservice/aidl/android/system/virtualizationcommon/ErrorCode.aidl b/virtualizationservice/aidl/android/system/virtualizationcommon/ErrorCode.aidl
new file mode 100644
index 0000000..04b9749
--- /dev/null
+++ b/virtualizationservice/aidl/android/system/virtualizationcommon/ErrorCode.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+package android.system.virtualizationcommon;
+
+/**
+ * Errors reported from within a VM.
+ */
+@Backing(type="int")
+enum ErrorCode {
+ /**
+ * Error code for all other errors not listed below.
+ */
+ UNKNOWN = 0,
+
+ /**
+ * Error code indicating that the payload can't be verified due to various reasons (e.g invalid
+ * merkle tree, invalid formats, etc).
+ */
+ PAYLOAD_VERIFICATION_FAILED = 1,
+
+ /**
+ * Error code indicating that the payload is verified, but has changed since the last boot.
+ */
+ PAYLOAD_CHANGED = 2,
+
+ /**
+ * Error code indicating that the payload config is invalid.
+ */
+ PAYLOAD_CONFIG_INVALID = 3,
+}
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachineCallback.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachineCallback.aidl
index 6c8eb4a..8d6ed08 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachineCallback.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachineCallback.aidl
@@ -15,6 +15,7 @@
*/
package android.system.virtualizationservice;
+import android.system.virtualizationcommon.ErrorCode;
import android.system.virtualizationservice.DeathReason;
/**
@@ -44,7 +45,7 @@
/**
* Called when an error occurs in the VM.
*/
- void onError(int cid, int errorCode, in String message);
+ void onError(int cid, ErrorCode errorCode, in String message);
/**
* Called when the VM dies.
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
index 8eb5497..d86f2bf 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
@@ -48,7 +48,7 @@
}
/** Debug level of the VM */
- DebugLevel debugLevel;
+ DebugLevel debugLevel = DebugLevel.NONE;
/** Whether the VM should be a protected VM. */
boolean protectedVm;
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineDebugInfo.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineDebugInfo.aidl
index 672c41a..bed4097 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineDebugInfo.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineDebugInfo.aidl
@@ -38,5 +38,5 @@
int requesterPid;
/** The current lifecycle state of the VM. */
- VirtualMachineState state;
+ VirtualMachineState state = VirtualMachineState.NOT_STARTED;
}
diff --git a/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl b/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
index dff5d46..e8c1724 100644
--- a/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
+++ b/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
@@ -15,6 +15,8 @@
*/
package android.system.virtualmachineservice;
+import android.system.virtualizationcommon.ErrorCode;
+
/** {@hide} */
interface IVirtualMachineService {
/**
@@ -51,28 +53,7 @@
void notifyPayloadFinished(int exitCode);
/**
- * Notifies that an error has occurred. See the ERROR_* constants.
+ * Notifies that an error has occurred inside the VM..
*/
- void notifyError(int errorCode, in String message);
-
- /**
- * Error code for all other errors not listed below.
- */
- const int ERROR_UNKNOWN = 0;
-
- /**
- * Error code indicating that the payload can't be verified due to various reasons (e.g invalid
- * merkle tree, invalid formats, etc).
- */
- const int ERROR_PAYLOAD_VERIFICATION_FAILED = 1;
-
- /**
- * Error code indicating that the payload is verified, but has changed since the last boot.
- */
- const int ERROR_PAYLOAD_CHANGED = 2;
-
- /**
- * Error code indicating that the payload config is invalid.
- */
- const int ERROR_PAYLOAD_INVALID_CONFIG = 3;
+ void notifyError(ErrorCode errorCode, in String message);
}
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 6a4cc93..352b4f1 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -39,12 +39,11 @@
self, BinderFeatures, ExceptionCode, Interface, LazyServiceGuard, ParcelFileDescriptor,
SpIBinder, Status, StatusCode, Strong, ThreadState,
};
-use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::{
- IVirtualMachineService::{
+use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::{
BnVirtualMachineService, IVirtualMachineService, VM_BINDER_SERVICE_PORT,
VM_STREAM_SERVICE_PORT, VM_TOMBSTONES_SERVICE_PORT,
- },
};
+use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::ErrorCode::ErrorCode;
use anyhow::{anyhow, bail, Context, Result};
use rpcbinder::run_rpc_server_with_factory;
use disk::QcowFile;
@@ -878,7 +877,7 @@
}
/// Call all registered callbacks to say that the VM encountered an error.
- pub fn notify_error(&self, cid: Cid, error_code: i32, message: &str) {
+ pub fn notify_error(&self, cid: Cid, error_code: ErrorCode, message: &str) {
let callbacks = &*self.0.lock().unwrap();
for callback in callbacks {
if let Err(e) = callback.onError(cid as i32, error_code, message) {
@@ -1116,7 +1115,7 @@
}
}
- fn notifyError(&self, error_code: i32, message: &str) -> binder::Result<()> {
+ fn notifyError(&self, error_code: ErrorCode, message: &str) -> binder::Result<()> {
let cid = self.cid;
if let Some(vm) = self.state.lock().unwrap().get_vm(cid) {
info!("VM having CID {} encountered an error", cid);
diff --git a/vm/src/run.rs b/vm/src/run.rs
index 058405e..aaa3988 100644
--- a/vm/src/run.rs
+++ b/vm/src/run.rs
@@ -28,7 +28,7 @@
use std::io::{self, BufRead, BufReader};
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::path::{Path, PathBuf};
-use vmclient::VmInstance;
+use vmclient::{ErrorCode, VmInstance};
use vmconfig::{open_parcel_file, VmConfig};
use zip::ZipArchive;
@@ -223,7 +223,7 @@
if let Some(path) = ramdump_path {
save_ramdump_if_available(path, &vm)?;
}
- println!("{}", death_reason);
+ println!("VM ended: {:?}", death_reason);
}
Ok(())
@@ -273,8 +273,8 @@
eprintln!("payload finished with exit code {}", exit_code);
}
- fn on_error(&self, _cid: i32, error_code: i32, message: &str) {
- eprintln!("VM encountered an error: code={}, message={}", error_code, message);
+ fn on_error(&self, _cid: i32, error_code: ErrorCode, message: &str) {
+ eprintln!("VM encountered an error: code={:?}, message={}", error_code, message);
}
}
diff --git a/vmclient/Android.bp b/vmclient/Android.bp
index 213125e..88b0c9a 100644
--- a/vmclient/Android.bp
+++ b/vmclient/Android.bp
@@ -8,6 +8,7 @@
srcs: ["src/lib.rs"],
edition: "2021",
rustlibs: [
+ "android.system.virtualizationcommon-rust",
"android.system.virtualizationservice-rust",
"libbinder_rs",
"liblog_rust",
diff --git a/vmclient/src/death_reason.rs b/vmclient/src/death_reason.rs
index b976f6f..fbf2523 100644
--- a/vmclient/src/death_reason.rs
+++ b/vmclient/src/death_reason.rs
@@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use std::fmt::{self, Debug, Display, Formatter};
use android_system_virtualizationservice::{
aidl::android::system::virtualizationservice::{
DeathReason::DeathReason as AidlDeathReason}};
@@ -96,48 +95,3 @@
}
}
}
-
-impl Display for DeathReason {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- let s = match self {
- Self::VirtualizationServiceDied => "VirtualizationService died.",
- Self::InfrastructureError => "Error waiting for VM to finish.",
- Self::Killed => "VM was killed.",
- Self::Unknown => "VM died for an unknown reason.",
- Self::Shutdown => "VM shutdown cleanly.",
- Self::Error => "Error starting VM.",
- Self::Reboot => "VM tried to reboot, possibly due to a kernel panic.",
- Self::Crash => "VM crashed.",
- Self::PvmFirmwarePublicKeyMismatch => {
- "pVM firmware failed to verify the VM because the public key doesn't match."
- }
- Self::PvmFirmwareInstanceImageChanged => {
- "pVM firmware failed to verify the VM because the instance image changed."
- }
- Self::BootloaderPublicKeyMismatch => {
- "Bootloader failed to verify the VM because the public key doesn't match."
- }
- Self::BootloaderInstanceImageChanged => {
- "Bootloader failed to verify the VM because the instance image changed."
- }
- Self::MicrodroidFailedToConnectToVirtualizationService => {
- "The microdroid failed to connect to VirtualizationService's RPC server."
- }
- Self::MicrodroidPayloadHasChanged => "The payload for microdroid is changed.",
- Self::MicrodroidPayloadVerificationFailed => {
- "The microdroid failed to verify given payload APK."
- }
- Self::MicrodroidInvalidPayloadConfig => {
- "The VM config for microdroid is invalid (e.g. missing tasks)."
- }
- Self::MicrodroidUnknownRuntimeError => {
- "There was a runtime error while running microdroid manager."
- }
- Self::Hangup => "VM hangup.",
- Self::Unrecognised(reason) => {
- return write!(f, "Unrecognised death reason {:?}.", reason);
- }
- };
- f.write_str(s)
- }
-}
diff --git a/vmclient/src/error_code.rs b/vmclient/src/error_code.rs
new file mode 100644
index 0000000..a7c442f
--- /dev/null
+++ b/vmclient/src/error_code.rs
@@ -0,0 +1,47 @@
+// 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.
+
+use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::ErrorCode::ErrorCode as AidlErrorCode;
+
+/// Errors reported from within a VM.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum ErrorCode {
+ /// Error code for all other errors not listed below.
+ Unknown,
+
+ /// Error code indicating that the payload can't be verified due to various reasons (e.g invalid
+ /// merkle tree, invalid formats, etc).
+ PayloadVerificationFailed,
+
+ /// Error code indicating that the payload is verified, but has changed since the last boot.
+ PayloadChanged,
+
+ /// Error code indicating that the payload config is invalid.
+ PayloadConfigInvalid,
+
+ /// Payload sent a death reason which was not recognised by the client library.
+ Unrecognised(AidlErrorCode),
+}
+
+impl From<AidlErrorCode> for ErrorCode {
+ fn from(error_code: AidlErrorCode) -> Self {
+ match error_code {
+ AidlErrorCode::UNKNOWN => Self::Unknown,
+ AidlErrorCode::PAYLOAD_VERIFICATION_FAILED => Self::PayloadVerificationFailed,
+ AidlErrorCode::PAYLOAD_CHANGED => Self::PayloadChanged,
+ AidlErrorCode::PAYLOAD_CONFIG_INVALID => Self::PayloadConfigInvalid,
+ _ => Self::Unrecognised(error_code),
+ }
+ }
+}
diff --git a/vmclient/src/errors.rs b/vmclient/src/errors.rs
index 231f81f..a6dca91 100644
--- a/vmclient/src/errors.rs
+++ b/vmclient/src/errors.rs
@@ -22,7 +22,7 @@
#[error("Timed out waiting for VM.")]
TimedOut,
/// The VM died before it was ready.
- #[error("VM died. ({reason})")]
+ #[error("VM died. ({reason:?})")]
Died {
/// The reason why the VM died.
reason: DeathReason,
diff --git a/vmclient/src/lib.rs b/vmclient/src/lib.rs
index 16b5d5a..e6f32b4 100644
--- a/vmclient/src/lib.rs
+++ b/vmclient/src/lib.rs
@@ -15,12 +15,15 @@
//! Client library for VirtualizationService.
mod death_reason;
+mod error_code;
mod errors;
mod sync;
pub use crate::death_reason::DeathReason;
+pub use crate::error_code::ErrorCode;
pub use crate::errors::VmWaitError;
use crate::sync::Monitor;
+use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::ErrorCode::ErrorCode as AidlErrorCode;
use android_system_virtualizationservice::{
aidl::android::system::virtualizationservice::{
DeathReason::DeathReason as AidlDeathReason,
@@ -83,7 +86,7 @@
/// 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) {}
+ fn on_error(&self, cid: i32, error_code: ErrorCode, 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.
@@ -294,9 +297,10 @@
Ok(())
}
- fn onError(&self, cid: i32, error_code: i32, message: &str) -> BinderResult<()> {
+ fn onError(&self, cid: i32, error_code: AidlErrorCode, message: &str) -> BinderResult<()> {
self.state.notify_state(VirtualMachineState::FINISHED);
if let Some(ref callback) = self.client_callback {
+ let error_code = error_code.into();
callback.on_error(cid, error_code, message);
}
Ok(())