Microdroid_manager reports error/finished as terminal events
Bug: 205778374
Test: atest --test-mapping packages/modules/Virtualization
Change-Id: Ie0223b6ed58a43ae6e92ed1aa56991445444488c
diff --git a/compos/compos_key_cmd/compos_key_cmd.cpp b/compos/compos_key_cmd/compos_key_cmd.cpp
index 76ff06f..27c7275 100644
--- a/compos/compos_key_cmd/compos_key_cmd.cpp
+++ b/compos/compos_key_cmd/compos_key_cmd.cpp
@@ -152,9 +152,13 @@
::ndk::ScopedAStatus onError(int32_t in_cid, int32_t in_error_code,
const std::string& in_message) override {
- // For now, just log the error as onDied() will follow.
LOG(WARNING) << "VM error! cid = " << in_cid << ", error_code = " << in_error_code
<< ", message = " << in_message;
+ {
+ std::unique_lock lock(mMutex);
+ mDied = true;
+ }
+ mCv.notify_all();
return ScopedAStatus::ok();
}
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachineCallback.java b/javalib/src/android/system/virtualmachine/VirtualMachineCallback.java
index 9dbed64..2ddaf30 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachineCallback.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachineCallback.java
@@ -33,7 +33,12 @@
public interface VirtualMachineCallback {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({ERROR_UNKNOWN, ERROR_PAYLOAD_VERIFICATION_FAILED, ERROR_PAYLOAD_CHANGED})
+ @IntDef({
+ ERROR_UNKNOWN,
+ ERROR_PAYLOAD_VERIFICATION_FAILED,
+ ERROR_PAYLOAD_CHANGED,
+ ERROR_PAYLOAD_INVALID_CONFIG
+ })
@interface ErrorCode {}
/** Error code for all other errors not listed below. */
@@ -48,6 +53,9 @@
/** Error code indicating that the payload is verified, but has changed since the last boot. */
int ERROR_PAYLOAD_CHANGED = 2;
+ /** Error code indicating that the payload config is invalid. */
+ int ERROR_PAYLOAD_INVALID_CONFIG = 3;
+
/** Called when the payload starts in the VM. */
void onPayloadStarted(@NonNull VirtualMachine vm, @Nullable ParcelFileDescriptor stream);
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 99ebc51..93a0759 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -39,7 +39,7 @@
use vsock::VsockStream;
use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::{
- ERROR_PAYLOAD_CHANGED, ERROR_PAYLOAD_VERIFICATION_FAILED, ERROR_UNKNOWN, VM_BINDER_SERVICE_PORT, VM_STREAM_SERVICE_PORT, 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);
@@ -66,6 +66,8 @@
PayloadChanged(String),
#[error("Payload verification has failed: {0}")]
PayloadVerificationFailed(String),
+ #[error("Payload config is invalid: {0}")]
+ InvalidConfig(String),
}
fn translate_error(err: &Error) -> (i32, String) {
@@ -75,6 +77,7 @@
MicrodroidError::PayloadVerificationFailed(msg) => {
(ERROR_PAYLOAD_VERIFICATION_FAILED, msg.to_string())
}
+ MicrodroidError::InvalidConfig(msg) => (ERROR_PAYLOAD_INVALID_CONFIG, msg.to_string()),
}
} else {
(ERROR_UNKNOWN, err.to_string())
@@ -112,16 +115,27 @@
info!("started.");
let service = get_vms_rpc_binder().context("cannot connect to VirtualMachineService")?;
- if let Err(err) = try_start_payload(&service) {
- let (error_code, message) = translate_error(&err);
- service.notifyError(error_code, &message)?;
- Err(err)
- } else {
- Ok(())
+ match try_run_payload(&service) {
+ Ok(code) => {
+ info!("notifying payload finished");
+ service.notifyPayloadFinished(code)?;
+ if code == 0 {
+ info!("task successfully finished");
+ } else {
+ error!("task exited with exit code: {}", code);
+ }
+ Ok(())
+ }
+ Err(err) => {
+ error!("task terminated: {:?}", err);
+ let (error_code, message) = translate_error(&err);
+ service.notifyError(error_code, &message)?;
+ Err(err)
+ }
}
}
-fn try_start_payload(service: &Strong<dyn IVirtualMachineService>) -> Result<()> {
+fn try_run_payload(service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
let metadata = load_metadata().context("Failed to load payload metadata")?;
let mut instance = InstanceDisk::new().context("Failed to load instance.img")?;
@@ -151,27 +165,26 @@
)
.context("Failed to run zipfuse")?;
- if !metadata.payload_config_path.is_empty() {
- let config = load_config(Path::new(&metadata.payload_config_path))?;
+ ensure!(
+ !metadata.payload_config_path.is_empty(),
+ MicrodroidError::InvalidConfig("No payload_config_path in metadata".to_string())
+ );
+ let config = load_config(Path::new(&metadata.payload_config_path))?;
- let fake_secret = "This is a placeholder for a value that is derived from the images that are loaded in the VM.";
- if let Err(err) = rustutils::system_properties::write("ro.vmsecret.keymint", fake_secret) {
- warn!("failed to set ro.vmsecret.keymint: {}", err);
- }
-
- // Wait until apex config is done. (e.g. linker configuration for apexes)
- // TODO(jooyung): wait until sys.boot_completed?
- wait_for_apex_config_done()?;
-
- if let Some(main_task) = &config.task {
- exec_task(main_task, service).map_err(|e| {
- error!("failed to execute task: {}", e);
- e
- })?;
- }
+ let fake_secret = "This is a placeholder for a value that is derived from the images that are loaded in the VM.";
+ if let Err(err) = rustutils::system_properties::write("ro.vmsecret.keymint", fake_secret) {
+ warn!("failed to set ro.vmsecret.keymint: {}", err);
}
- Ok(())
+ // Wait until apex config is done. (e.g. linker configuration for apexes)
+ // TODO(jooyung): wait until sys.boot_completed?
+ wait_for_apex_config_done()?;
+
+ ensure!(
+ config.task.is_some(),
+ MicrodroidError::InvalidConfig("No task in VM config".to_string())
+ );
+ exec_task(&config.task.unwrap(), service)
}
struct ApkDmverityArgument<'a> {
@@ -305,7 +318,7 @@
/// Executes the given task. Stdout of the task is piped into the vsock stream to the
/// virtualizationservice in the host side.
-fn exec_task(task: &Task, service: &Strong<dyn IVirtualMachineService>) -> Result<()> {
+fn exec_task(task: &Task, service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
info!("executing main task {:?}...", task);
let mut command = build_command(task)?;
@@ -319,19 +332,7 @@
}
let exit_status = command.spawn()?.wait()?;
- if let Some(code) = exit_status.code() {
- info!("notifying payload finished");
- service.notifyPayloadFinished(code)?;
-
- if code == 0 {
- info!("task successfully finished");
- } else {
- error!("task exited with exit code: {}", code);
- }
- } else {
- error!("task terminated: {}", exit_status);
- }
- Ok(())
+ exit_status.code().ok_or_else(|| anyhow!("Failed to get exit_code from the paylaod."))
}
fn build_command(task: &Task) -> Result<Command> {
diff --git a/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl b/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
index 97f6ca3..1a16f2a 100644
--- a/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
+++ b/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
@@ -64,4 +64,9 @@
* 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;
}