Load crashkernel using kexec

Microdroid_manager executes the kexec binary as part of the boot process
if ramdumping is supported.

Bug: 238404545
Test: boot microdroid
Change-Id: Ie9835b427dd0e556bf21a004cea070d553b829a8
diff --git a/microdroid/kdump/Android.bp b/microdroid/kdump/Android.bp
index 390886b..cc681a7 100644
--- a/microdroid/kdump/Android.bp
+++ b/microdroid/kdump/Android.bp
@@ -4,9 +4,10 @@
 
 cc_binary {
     name: "microdroid_kexec",
-    stem: "kexec",
+    stem: "kexec_load",
     srcs: ["kexec.c"],
     installable: false,
+    static_executable: true, // required because this runs before linkerconfig
     compile_multilib: "64",
 }
 
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 531c707..eb53337 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -166,6 +166,8 @@
     let _ = kernlog::init();
     info!("started.");
 
+    load_crashkernel_if_supported().context("Failed to load crashkernel")?;
+
     let service = get_vms_rpc_binder()
         .context("cannot connect to VirtualMachineService")
         .map_err(|e| MicrodroidError::FailedToConnectToVirtualizationService(e.to_string()))?;
@@ -610,6 +612,20 @@
     Ok(serde_json::from_reader(file)?)
 }
 
+/// Loads the crashkernel into memory using kexec if the VM is loaded with `crashkernel=' parameter
+/// in the cmdline.
+fn load_crashkernel_if_supported() -> Result<()> {
+    let supported = std::fs::read_to_string("/proc/cmdline")?.contains(" crashkernel=");
+    info!("ramdump supported: {}", supported);
+    if supported {
+        let status = Command::new("/system/bin/kexec_load").status()?;
+        if !status.success() {
+            return Err(anyhow!("Failed to load crashkernel: {:?}", status));
+        }
+    }
+    Ok(())
+}
+
 /// 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<i32> {