Merge "Add document about using lldbclient.py"
diff --git a/compos/Android.bp b/compos/Android.bp
index ea7c4d6..0890e9d 100644
--- a/compos/Android.bp
+++ b/compos/Android.bp
@@ -7,7 +7,6 @@
     edition: "2021",
     srcs: ["src/compsvc_main.rs"],
     rustlibs: [
-        "android.system.virtualmachineservice-rust",
         "authfs_aidl_interface-rust",
         "compos_aidl_interface-rust",
         "libandroid_logger",
@@ -24,6 +23,7 @@
         "librpcbinder_rs",
         "librustutils",
         "libscopeguard",
+        "libvm_payload_bindgen",
     ],
     prefer_rlib: true,
     shared_libs: [
diff --git a/compos/compos_key_helper/compos_key_main.cpp b/compos/compos_key_helper/compos_key_main.cpp
index 224e42b..4fb0762 100644
--- a/compos/compos_key_helper/compos_key_main.cpp
+++ b/compos/compos_key_helper/compos_key_main.cpp
@@ -20,6 +20,7 @@
 #include <vm_payload.h>
 
 #include <string_view>
+#include <vector>
 
 #include "compos_key.h"
 
@@ -37,8 +38,9 @@
 
 Result<Ed25519KeyPair> getSigningKey() {
     Seed seed;
-    if (!get_vm_instance_secret(kSigningKeySeedIdentifier, strlen(kSigningKeySeedIdentifier),
-                                seed.data(), seed.size())) {
+    if (!AVmPayload_getVmInstanceSecret(kSigningKeySeedIdentifier,
+                                        strlen(kSigningKeySeedIdentifier), seed.data(),
+                                        seed.size())) {
         return Error() << "Failed to get signing key seed";
     }
     return compos_key::keyFromSeed(seed);
@@ -58,14 +60,18 @@
 }
 
 int write_bcc() {
-    uint8_t bcc[4096];
-    size_t bcc_size = get_dice_attestation_chain(bcc, sizeof(bcc));
-    if (bcc_size == 0) {
+    size_t bcc_size;
+    if (!AVmPayload_getDiceAttestationChain(nullptr, 0, &bcc_size)) {
+        LOG(ERROR) << "Failed to measure attestation chain";
+        return 1;
+    }
+    std::vector<uint8_t> bcc(bcc_size);
+    if (!AVmPayload_getDiceAttestationChain(bcc.data(), bcc.size(), &bcc_size)) {
         LOG(ERROR) << "Failed to get attestation chain";
         return 1;
     }
 
-    if (!WriteFully(STDOUT_FILENO, bcc, bcc_size)) {
+    if (!WriteFully(STDOUT_FILENO, bcc.data(), bcc.size())) {
         PLOG(ERROR) << "Write failed";
         return 1;
     }
diff --git a/compos/src/compsvc_main.rs b/compos/src/compsvc_main.rs
index 16d258e..991725d 100644
--- a/compos/src/compsvc_main.rs
+++ b/compos/src/compsvc_main.rs
@@ -22,20 +22,12 @@
 mod compsvc;
 mod fsverity;
 
-use android_system_virtualmachineservice::{
-    aidl::android::system::virtualmachineservice::IVirtualMachineService::{
-        IVirtualMachineService, VM_BINDER_SERVICE_PORT,
-    },
-    binder::Strong,
-};
-use anyhow::{bail, Context, Result};
+use anyhow::{bail, Result};
 use compos_common::COMPOS_VSOCK_PORT;
 use log::{debug, error};
-use rpcbinder::{get_vsock_rpc_interface, run_rpc_server};
+use rpcbinder::run_rpc_server;
 use std::panic;
-
-/// The CID representing the host VM
-const VMADDR_CID_HOST: u32 = 2;
+use vm_payload_bindgen::AVmPayload_notifyPayloadReady;
 
 fn main() {
     if let Err(e) = try_main() {
@@ -54,14 +46,10 @@
     }));
 
     let service = compsvc::new_binder()?.as_binder();
-    let vm_service = get_vm_service()?;
-
     debug!("compsvc is starting as a rpc service.");
-
-    let retval = run_rpc_server(service, COMPOS_VSOCK_PORT, || {
-        if let Err(e) = vm_service.notifyPayloadReady() {
-            error!("Unable to notify ready: {}", e);
-        }
+    // SAFETY: Invokes a method from the bindgen library `vm_payload_bindgen`.
+    let retval = run_rpc_server(service, COMPOS_VSOCK_PORT, || unsafe {
+        AVmPayload_notifyPayloadReady();
     });
     if retval {
         debug!("RPC server has shut down gracefully");
@@ -70,8 +58,3 @@
         bail!("Premature termination of RPC server");
     }
 }
-
-fn get_vm_service() -> Result<Strong<dyn IVirtualMachineService>> {
-    get_vsock_rpc_interface(VMADDR_CID_HOST, VM_BINDER_SERVICE_PORT as u32)
-        .context("Connecting to IVirtualMachineService")
-}
diff --git a/microdroid/vm_payload/Android.bp b/microdroid/vm_payload/Android.bp
index 4bfe603..a68595f 100644
--- a/microdroid/vm_payload/Android.bp
+++ b/microdroid/vm_payload/Android.bp
@@ -19,3 +19,15 @@
         "com.android.compos",
     ],
 }
+
+rust_bindgen {
+    name: "libvm_payload_bindgen",
+    wrapper_src: "include/vm_payload.h",
+    crate_name: "vm_payload_bindgen",
+    source_stem: "bindings",
+    apex_available: ["com.android.compos"],
+    visibility: ["//packages/modules/Virtualization/compos"],
+    shared_libs: [
+        "libvm_payload",
+    ],
+}
diff --git a/microdroid/vm_payload/include/vm_payload.h b/microdroid/vm_payload/include/vm_payload.h
index 4b77b43..05abdce 100644
--- a/microdroid/vm_payload/include/vm_payload.h
+++ b/microdroid/vm_payload/include/vm_payload.h
@@ -18,7 +18,6 @@
 
 #include <stdbool.h>
 #include <stddef.h>
-#include <stdint.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -26,9 +25,10 @@
 
 /**
  * Notifies the host that the payload is ready.
- * Returns true if the notification succeeds else false.
+ *
+ * \return true if the notification succeeds else false.
  */
-bool notify_payload_ready();
+bool AVmPayload_notifyPayloadReady(void);
 
 /**
  * Get a secret that is uniquely bound to this VM instance. The secrets are 32-byte values and the
@@ -41,23 +41,35 @@
  *
  * \return true on success and false on failure.
  */
-bool get_vm_instance_secret(const void *identifier, size_t identifier_size, void *secret,
-                            size_t size);
+bool AVmPayload_getVmInstanceSecret(const void *identifier, size_t identifier_size, void *secret,
+                                    size_t size);
 
 /**
- * Get the VM's attestation chain.
- * Returns the size of data or 0 on failure.
+ * Get the VM's DICE attestation chain.
+ *
  * TODO: don't expose the contained privacy breaking identifiers to the payload
  * TODO: keep the DICE chain as an internal detail for as long as possible
+ *
+ * \param data pointer to size bytes where the chain is written.
+ * \param size number of bytes that can be written to data.
+ * \param total outputs the total size of the chain if the function succeeds
+ *
+ * \return true on success and false on failure.
  */
-size_t get_dice_attestation_chain(void *data, size_t size);
+bool AVmPayload_getDiceAttestationChain(void *data, size_t size, size_t *total);
 
 /**
- * Get the VM's attestation CDI.
- * Returns the size of data or 0 on failure.
+ * Get the VM's DICE attestation CDI.
+ *
  * TODO: don't expose the raw CDI, only derived values
+ *
+ * \param data pointer to size bytes where the CDI is written.
+ * \param size number of bytes that can be written to data.
+ * \param total outputs the total size of the CDI if the function succeeds
+ *
+ * \return true on success and false on failure.
  */
-size_t get_dice_attestation_cdi(void *data, size_t size);
+bool AVmPayload_getDiceAttestationCdi(void *data, size_t size, size_t *total);
 
 #ifdef __cplusplus
 } // extern "C"
diff --git a/microdroid/vm_payload/src/lib.rs b/microdroid/vm_payload/src/lib.rs
index 74dd8f4..ca0c17b 100644
--- a/microdroid/vm_payload/src/lib.rs
+++ b/microdroid/vm_payload/src/lib.rs
@@ -17,6 +17,6 @@
 mod vm_service;
 
 pub use vm_service::{
-    get_dice_attestation_cdi, get_dice_attestation_chain, get_vm_instance_secret,
-    notify_payload_ready,
+    AVmPayload_getDiceAttestationCdi, AVmPayload_getDiceAttestationChain,
+    AVmPayload_getVmInstanceSecret, AVmPayload_notifyPayloadReady,
 };
diff --git a/microdroid/vm_payload/src/vm_service.rs b/microdroid/vm_payload/src/vm_service.rs
index cfc3884..44013c9 100644
--- a/microdroid/vm_payload/src/vm_service.rs
+++ b/microdroid/vm_payload/src/vm_service.rs
@@ -23,7 +23,7 @@
 /// Notifies the host that the payload is ready.
 /// Returns true if the notification succeeds else false.
 #[no_mangle]
-pub extern "C" fn notify_payload_ready() -> bool {
+pub extern "C" fn AVmPayload_notifyPayloadReady() -> bool {
     android_logger::init_once(
         android_logger::Config::default().with_tag("vm_payload").with_min_level(Level::Debug),
     );
@@ -46,9 +46,14 @@
 ///
 /// # Safety
 ///
-/// The identifier must be identifier_size bytes and secret must be size bytes.
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `identifier` must be [valid] for reads of `identifier_size` bytes.
+/// * `secret` must be [valid] for writes of `size` bytes.
+///
+/// [valid]: std::ptr#safety
 #[no_mangle]
-pub unsafe extern "C" fn get_vm_instance_secret(
+pub unsafe extern "C" fn AVmPayload_getVmInstanceSecret(
     identifier: *const u8,
     identifier_size: usize,
     secret: *mut u8,
@@ -77,25 +82,31 @@
 }
 
 /// Get the VM's attestation chain.
-/// Returns the size of data or 0 on failure.
+/// Returns true on success, else false.
 ///
 /// # Safety
 ///
-/// The data must be size bytes big.
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `data` must be [valid] for writes of `size` bytes.
+/// * `total` must be [valid] for writes.
+///
+/// [valid]: std::ptr#safety
 #[no_mangle]
-pub unsafe extern "C" fn get_dice_attestation_chain(data: *mut u8, size: usize) -> usize {
+pub unsafe extern "C" fn AVmPayload_getDiceAttestationChain(
+    data: *mut u8,
+    size: usize,
+    total: *mut usize,
+) -> bool {
     match try_get_dice_attestation_chain() {
         Err(e) => {
             error!("{:?}", e);
-            0
+            false
         }
         Ok(chain) => {
-            if size < chain.len() {
-                0
-            } else {
-                std::ptr::copy_nonoverlapping(chain.as_ptr(), data, chain.len());
-                chain.len()
-            }
+            total.write(chain.len());
+            std::ptr::copy_nonoverlapping(chain.as_ptr(), data, std::cmp::min(chain.len(), size));
+            true
         }
     }
 }
@@ -105,25 +116,31 @@
 }
 
 /// Get the VM's attestation CDI.
-/// Returns the size of data or 0 on failure.
+/// Returns true on success, else false.
 ///
 /// # Safety
 ///
-/// The data must be size bytes big.
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `data` must be [valid] for writes of `size` bytes.
+/// * `total` must be [valid] for writes.
+///
+/// [valid]: std::ptr#safety
 #[no_mangle]
-pub unsafe extern "C" fn get_dice_attestation_cdi(data: *mut u8, size: usize) -> usize {
+pub unsafe extern "C" fn AVmPayload_getDiceAttestationCdi(
+    data: *mut u8,
+    size: usize,
+    total: *mut usize,
+) -> bool {
     match try_get_dice_attestation_cdi() {
         Err(e) => {
             error!("{:?}", e);
-            0
+            false
         }
         Ok(cdi) => {
-            if size < cdi.len() {
-                0
-            } else {
-                std::ptr::copy_nonoverlapping(cdi.as_ptr(), data, cdi.len());
-                cdi.len()
-            }
+            total.write(cdi.len());
+            std::ptr::copy_nonoverlapping(cdi.as_ptr(), data, std::cmp::min(cdi.len(), size));
+            true
         }
     }
 }
diff --git a/tests/benchmark/Android.bp b/tests/benchmark/Android.bp
index acd0f09..e3f4685 100644
--- a/tests/benchmark/Android.bp
+++ b/tests/benchmark/Android.bp
@@ -46,6 +46,7 @@
         "libbinder_ndk",
         "libbinder_rpc_unstable",
         "liblog",
+        "libvm_payload",
     ],
 }
 
diff --git a/tests/benchmark/src/native/benchmarkbinary.cpp b/tests/benchmark/src/native/benchmarkbinary.cpp
index 8694ef9..4e3c14d 100644
--- a/tests/benchmark/src/native/benchmarkbinary.cpp
+++ b/tests/benchmark/src/native/benchmarkbinary.cpp
@@ -26,6 +26,7 @@
 #include <stdio.h>
 #include <time.h>
 #include <unistd.h>
+#include <vm_payload.h>
 
 #include <binder_rpc_unstable.hpp>
 #include <fstream>
@@ -157,19 +158,8 @@
 Result<void> run_io_benchmark_tests() {
     auto test_service = ndk::SharedRefBase::make<IOBenchmarkService>();
     auto callback = []([[maybe_unused]] void* param) {
-        // Tell microdroid_manager that we're ready.
-        // If we can't, abort in order to fail fast - the host won't proceed without
-        // receiving the onReady signal.
-        ndk::SpAIBinder binder(
-                RpcClient(VMADDR_CID_HOST, IVirtualMachineService::VM_BINDER_SERVICE_PORT));
-        auto vm_service = IVirtualMachineService::fromBinder(binder);
-        if (vm_service == nullptr) {
-            LOG(ERROR) << "failed to connect VirtualMachineService\n";
-            abort();
-        }
-        if (auto status = vm_service->notifyPayloadReady(); !status.isOk()) {
-            LOG(ERROR) << "failed to notify payload ready to virtualizationservice: "
-                       << status.getDescription();
+        if (!AVmPayload_notifyPayloadReady()) {
+            LOG(ERROR) << "failed to notify payload ready to virtualizationservice";
             abort();
         }
     };
diff --git a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
index 2deeb70..c2fd295 100644
--- a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
+++ b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
@@ -150,7 +150,7 @@
             if (!mVcpuStartedNanoTime.isPresent()) {
                 mVcpuStartedNanoTime = OptionalLong.of(System.nanoTime());
             }
-            if (log.contains("Starting kernel") && !mKernelStartedNanoTime.isPresent()) {
+            if (log.contains("Starting payload...") && !mKernelStartedNanoTime.isPresent()) {
                 mKernelStartedNanoTime = OptionalLong.of(System.nanoTime());
             }
             if (log.contains("Run /init as init process") && !mInitStartedNanoTime.isPresent()) {
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index 5d6e901..003aca8 100644
--- a/tests/testapk/src/native/testbinary.cpp
+++ b/tests/testapk/src/native/testbinary.cpp
@@ -75,41 +75,48 @@
 
         ndk::ScopedAStatus insecurelyExposeVmInstanceSecret(std::vector<uint8_t>* out) override {
             const uint8_t identifier[] = {1, 2, 3, 4};
-            uint8_t secret[32];
-            if (!get_vm_instance_secret(identifier, sizeof(identifier), secret, sizeof(secret))) {
+            out->resize(32);
+            if (!AVmPayload_getVmInstanceSecret(identifier, sizeof(identifier), out->data(),
+                                                out->size())) {
                 return ndk::ScopedAStatus::
                         fromServiceSpecificErrorWithMessage(0, "Failed to VM instance secret");
             }
-            *out = {secret, secret + sizeof(secret)};
             return ndk::ScopedAStatus::ok();
         }
 
         ndk::ScopedAStatus insecurelyExposeAttestationCdi(std::vector<uint8_t>* out) override {
-            uint8_t cdi[64];
-            size_t cdi_size = get_dice_attestation_cdi(cdi, sizeof(cdi));
-            if (cdi_size == 0) {
+            size_t cdi_size;
+            if (!AVmPayload_getDiceAttestationCdi(nullptr, 0, &cdi_size)) {
+                return ndk::ScopedAStatus::
+                        fromServiceSpecificErrorWithMessage(0, "Failed to measure attestation cdi");
+            }
+            out->resize(cdi_size);
+            if (!AVmPayload_getDiceAttestationCdi(out->data(), out->size(), &cdi_size)) {
                 return ndk::ScopedAStatus::
                         fromServiceSpecificErrorWithMessage(0, "Failed to get attestation cdi");
             }
-            *out = {cdi, cdi + cdi_size};
             return ndk::ScopedAStatus::ok();
         }
 
         ndk::ScopedAStatus getBcc(std::vector<uint8_t>* out) override {
-            uint8_t bcc[4096];
-            size_t bcc_size = get_dice_attestation_chain(bcc, sizeof(bcc));
-            if (bcc_size == 0) {
+            size_t bcc_size;
+            if (!AVmPayload_getDiceAttestationChain(nullptr, 0, &bcc_size)) {
+                return ndk::ScopedAStatus::
+                        fromServiceSpecificErrorWithMessage(0,
+                                                            "Failed to measure attestation chain");
+            }
+            out->resize(bcc_size);
+            if (!AVmPayload_getDiceAttestationChain(out->data(), out->size(), &bcc_size)) {
                 return ndk::ScopedAStatus::
                         fromServiceSpecificErrorWithMessage(0, "Failed to get attestation chain");
             }
-            *out = {bcc, bcc + bcc_size};
             return ndk::ScopedAStatus::ok();
         }
     };
     auto testService = ndk::SharedRefBase::make<TestService>();
 
     auto callback = []([[maybe_unused]] void* param) {
-        if (!notify_payload_ready()) {
+        if (!AVmPayload_notifyPayloadReady()) {
             std::cerr << "failed to notify payload ready to virtualizationservice" << std::endl;
             abort();
         }
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/DeathReason.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/DeathReason.aidl
index dceabf1..416eb7b 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/DeathReason.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/DeathReason.aidl
@@ -54,4 +54,6 @@
     MICRODROID_UNKNOWN_RUNTIME_ERROR = 15,
     /** The VM killed due to hangup */
     HANGUP = 16,
+    /** The VCPU stalled */
+    WATCHDOG_REBOOT = 17,
 }
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 563fab0..973bfa3 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -63,7 +63,7 @@
 use std::sync::{Arc, Mutex, Weak};
 use tombstoned_client::{TombstonedConnection, DebuggerdDumpType};
 use vmconfig::VmConfig;
-use vsock::{SockAddr, VsockListener, VsockStream};
+use vsock::{VsockListener, VsockStream};
 use zip::ZipArchive;
 
 pub const BINDER_SERVICE_IDENTIFIER: &str = "android.system.virtualizationservice";
@@ -268,7 +268,7 @@
 }
 
 fn handle_tombstone(stream: &mut VsockStream) -> Result<()> {
-    if let Ok(SockAddr::Vsock(addr)) = stream.peer_addr() {
+    if let Ok(addr) = stream.peer_addr() {
         info!("Vsock Stream connected to cid={} for tombstones", addr.cid());
     }
     let tb_connection =
@@ -499,7 +499,7 @@
             }
             Ok(s) => s,
         };
-        if let Ok(SockAddr::Vsock(addr)) = stream.peer_addr() {
+        if let Ok(addr) = stream.peer_addr() {
             let cid = addr.cid();
             let port = addr.port();
             info!("payload stream connected from cid={}, port={}", cid, port);
diff --git a/virtualizationservice/src/crosvm.rs b/virtualizationservice/src/crosvm.rs
index ff1116a..54cdeb6 100644
--- a/virtualizationservice/src/crosvm.rs
+++ b/virtualizationservice/src/crosvm.rs
@@ -58,6 +58,8 @@
 const CROSVM_REBOOT_STATUS: i32 = 32;
 /// The exit status which crosvm returns when it crashes due to an error.
 const CROSVM_CRASH_STATUS: i32 = 33;
+/// The exit status which crosvm returns when vcpu is stalled.
+const CROSVM_WATCHDOG_REBOOT_STATUS: i32 = 36;
 
 lazy_static! {
     /// If the VM doesn't move to the Started state within this amount time, a hang-up error is
@@ -247,7 +249,14 @@
         let result = child.wait();
         match &result {
             Err(e) => error!("Error waiting for crosvm({}) instance to die: {}", child.id(), e),
-            Ok(status) => info!("crosvm({}) exited with status {}", child.id(), status),
+            Ok(status) => {
+                info!("crosvm({}) exited with status {}", child.id(), status);
+                if let Some(exit_status_code) = status.code() {
+                    if exit_status_code == CROSVM_WATCHDOG_REBOOT_STATUS {
+                        info!("detected vcpu stall on crosvm");
+                    }
+                }
+            }
         }
 
         let mut vm_state = self.vm_state.lock().unwrap();
@@ -421,6 +430,7 @@
             Some(CROSVM_ERROR_STATUS) => DeathReason::ERROR,
             Some(CROSVM_REBOOT_STATUS) => DeathReason::REBOOT,
             Some(CROSVM_CRASH_STATUS) => DeathReason::CRASH,
+            Some(CROSVM_WATCHDOG_REBOOT_STATUS) => DeathReason::WATCHDOG_REBOOT,
             Some(_) => DeathReason::UNKNOWN,
         }
     } else {