Add notifyError/onError notification for VM errors

For now, microdroid_manager shuts down a VM instance when it fails to
verify the VM payload. This change adds a new "error" notification to
deliver the error to the VM app.

Fow now this doesn't change the workflow. In a follow-up change this
will be changed so that VM app can decide to shutdown or not "onError".

Bug: 205778374
Test: MicrodroidHostTestCases
Change-Id: If7fdac3996b69601be0eda17da3e4cf218b4d1d8
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 5d64684..1c88174 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -714,6 +714,16 @@
         }
     }
 
+    /// Call all registered callbacks to say that the VM encountered an error.
+    pub fn notify_error(&self, cid: Cid, error_code: i32, message: &str) {
+        let callbacks = &*self.0.lock().unwrap();
+        for callback in callbacks {
+            if let Err(e) = callback.onError(cid as i32, error_code, message) {
+                error!("Error notifying error event from VM CID {}: {}", cid, e);
+            }
+        }
+    }
+
     /// Call all registered callbacks to say that the VM has died.
     pub fn callback_on_died(&self, cid: Cid) {
         let callbacks = &*self.0.lock().unwrap();
@@ -879,10 +889,10 @@
             vm.callbacks.notify_payload_started(cid, stream);
             Ok(())
         } else {
-            error!("notifyPayloadStarted is called from an unknown cid {}", cid);
+            error!("notifyPayloadStarted is called from an unknown CID {}", cid);
             Err(new_binder_exception(
                 ExceptionCode::SERVICE_SPECIFIC,
-                format!("cannot find a VM with cid {}", cid),
+                format!("cannot find a VM with CID {}", cid),
             ))
         }
     }
@@ -896,10 +906,10 @@
             vm.callbacks.notify_payload_ready(cid);
             Ok(())
         } else {
-            error!("notifyPayloadReady is called from an unknown cid {}", cid);
+            error!("notifyPayloadReady is called from an unknown CID {}", cid);
             Err(new_binder_exception(
                 ExceptionCode::SERVICE_SPECIFIC,
-                format!("cannot find a VM with cid {}", cid),
+                format!("cannot find a VM with CID {}", cid),
             ))
         }
     }
@@ -913,10 +923,27 @@
             vm.callbacks.notify_payload_finished(cid, exit_code);
             Ok(())
         } else {
-            error!("notifyPayloadFinished is called from an unknown cid {}", cid);
+            error!("notifyPayloadFinished is called from an unknown CID {}", cid);
             Err(new_binder_exception(
                 ExceptionCode::SERVICE_SPECIFIC,
-                format!("cannot find a VM with cid {}", cid),
+                format!("cannot find a VM with CID {}", cid),
+            ))
+        }
+    }
+
+    fn notifyError(&self, error_code: i32, 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);
+            vm.update_payload_state(PayloadState::Finished)
+                .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))?;
+            vm.callbacks.notify_error(cid, error_code, message);
+            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),
             ))
         }
     }