cras: Include the panic message in crash reports

BUG=b:410986360
TEST=CRAS_RUST_PANIC_FOR_TESTING=1 cras-dev.sh
TEST=grep "sig=panicked at 'panicing due to CRAS_RUST_PANIC_FOR_TESTING'" /var/spool/crash/cras.*.meta

Cq-Depend: chromium:6461145
Change-Id: I442532c0376a5d21d3d9d9bf0743fead248de4d8
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/adhd/+/6458258
Reviewed-by: Judy Hsiao <judyhsiao@google.com>
Tested-by: chromeos-cop-builder@chromeos-cop.iam.gserviceaccount.com <chromeos-cop-builder@chromeos-cop.iam.gserviceaccount.com>
Commit-Queue: Li-Yu Yu <aaronyu@google.com>
diff --git a/Cargo.Bazel.lock b/Cargo.Bazel.lock
index 0a5f989..88aed8f 100644
--- a/Cargo.Bazel.lock
+++ b/Cargo.Bazel.lock
@@ -1,5 +1,5 @@
 {
-  "checksum": "906f78015cf287bd0fd4588276b672e85903d38d684ba36f749c6ef1a8aa6813",
+  "checksum": "353a91642f2498ff711be3842974d196bda9ce7ed38873ff2c2187cd334b8ed2",
   "crates": {
     "addr2line 0.20.0": {
       "name": "addr2line",
@@ -2020,6 +2020,10 @@
               "target": "bitflags"
             },
             {
+              "id": "cfg-if 1.0.0",
+              "target": "cfg_if"
+            },
+            {
               "id": "getrandom 0.2.10",
               "target": "getrandom"
             },
diff --git a/Cargo.lock b/Cargo.lock
index 803212d..8907585 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -327,9 +327,11 @@
 dependencies = [
  "anyhow",
  "bitflags 2.4.0",
+ "cfg-if",
  "getrandom",
  "itertools",
  "libc",
+ "libchromeos",
  "log",
  "nix 0.28.0",
  "once_cell",
@@ -852,6 +854,10 @@
 checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 
 [[package]]
+name = "libchromeos"
+version = "0.1.0"
+
+[[package]]
 name = "libdbus-sys"
 version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 53625ac..c9cf132 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -91,6 +91,7 @@
 # ChromiumOS crates
 system_api = "*"  # provided by ebuild
 featured = "*"  # provided by ebuild
+libchromeos = "*"  # provided by ebuild
 
 [patch.crates-io]
 # When building out of ChromiumOS, we do not actually use system_api.
@@ -104,3 +105,4 @@
 # system_api = { path = "../../platform2/system_api" } # ignored by ebuild
 
 featured = { path = "repositories/featured_stub" } # ignored by ebuild
+libchromeos = { path = "repositories/libchromeos_stub" } # ignored by ebuild
diff --git a/cras/common/Cargo.toml b/cras/common/Cargo.toml
index e382c6c..482519f 100644
--- a/cras/common/Cargo.toml
+++ b/cras/common/Cargo.toml
@@ -6,6 +6,7 @@
 [dependencies]
 anyhow = "1.0.68"
 bitflags = { version = "2.4.0", features = ["serde"] }
+cfg-if = "1.0.0"
 getrandom = "0.2.7"
 itertools = "0.11.0"
 libc = "0.2.44"
@@ -18,3 +19,9 @@
 static_assertions = "1.1.0"
 syslog = "6.0.1"
 zerocopy = "0.7.32"
+
+# ChromiumOS crates
+libchromeos = { version = "*", optional = true }  # provided by ebuild
+
+[features]
+chromiumos = ["libchromeos"]
diff --git a/cras/common/rust_common.h b/cras/common/rust_common.h
index fb4ba46..f76546d 100644
--- a/cras/common/rust_common.h
+++ b/cras/common/rust_common.h
@@ -109,6 +109,11 @@
 int cras_rust_init_logging(void);
 
 /**
+ * Install a panic hook to allow the panic message to be included in crash reports.
+ */
+void cras_rust_register_panic_hook(void);
+
+/**
  * Pseudonymize the stable_id using the global salt.
  * Returns the salted stable_id.
  */
diff --git a/cras/common/src/lib.rs b/cras/common/src/lib.rs
index a931b1f..bc45c2a 100644
--- a/cras/common/src/lib.rs
+++ b/cras/common/src/lib.rs
@@ -4,6 +4,7 @@
 
 pub mod fra;
 pub mod logging;
+pub mod panic;
 pub mod pseudonymization;
 pub mod string;
 pub mod types_internal;
diff --git a/cras/common/src/panic.rs b/cras/common/src/panic.rs
new file mode 100644
index 0000000..ae8dc3e
--- /dev/null
+++ b/cras/common/src/panic.rs
@@ -0,0 +1,22 @@
+// Copyright 2025 The ChromiumOS Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use cfg_if::cfg_if;
+
+#[no_mangle]
+/// Install a panic hook to allow the panic message to be included in crash reports.
+pub extern "C" fn cras_rust_register_panic_hook() {
+    cfg_if! {
+        if #[cfg(feature = "chromiumos")] {
+            libchromeos::panic_handler::install_memfd_handler();
+        } else {
+            log::info!(r#"cras_rust_register_panic_hook() doing nothing without feature = "chromiumos""#);
+        }
+    }
+
+    const CRAS_RUST_PANIC_FOR_TESTING: &str = "CRAS_RUST_PANIC_FOR_TESTING";
+    if std::env::var(CRAS_RUST_PANIC_FOR_TESTING).is_ok() {
+        panic!("panicing due to {CRAS_RUST_PANIC_FOR_TESTING}")
+    }
+}
diff --git a/cras/src/server/cras_server.c b/cras/src/server/cras_server.c
index dd1f688..881548c 100644
--- a/cras/src/server/cras_server.c
+++ b/cras/src/server/cras_server.c
@@ -398,6 +398,7 @@
   if (cras_rust_init_logging()) {
     syslog(LOG_ERR, "cannot initialize logging in cras_rust");
   }
+  cras_rust_register_panic_hook();
   cras_alsa_lib_error_handler_init();
 
   server_instance.next_client_id = RESERVED_CLIENT_IDS;
diff --git a/repositories/libchromeos_stub/Cargo.toml b/repositories/libchromeos_stub/Cargo.toml
new file mode 100644
index 0000000..c9164aa
--- /dev/null
+++ b/repositories/libchromeos_stub/Cargo.toml
@@ -0,0 +1,5 @@
+[package]
+name = "libchromeos"
+version = "0.1.0"
+authors = ["The ChromiumOS Authors"]
+edition = "2021"
diff --git a/repositories/libchromeos_stub/src/lib.rs b/repositories/libchromeos_stub/src/lib.rs
new file mode 100644
index 0000000..73c1588
--- /dev/null
+++ b/repositories/libchromeos_stub/src/lib.rs
@@ -0,0 +1,3 @@
+// Copyright 2025 The ChromiumOS Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.