Loading debuggerd/TEST_MAPPING +3 −0 Original line number Original line Diff line number Diff line Loading @@ -2,6 +2,9 @@ "presubmit": [ "presubmit": [ { { "name": "debuggerd_test" "name": "debuggerd_test" }, { "name": "libtombstoned_client_rust_test" } } ] ] } } debuggerd/rust/tombstoned_client/Android.bp 0 → 100644 +58 −0 Original line number Original line Diff line number Diff line package { default_applicable_licenses: ["Android-Apache-2.0"], } cc_library_static { name: "libtombstoned_client_wrapper", srcs: [ "wrapper.cpp", ], generated_sources: [ "libtombstoned_client_rust_bridge_code" ], header_libs: [ "libbase_headers", "libdebuggerd_common_headers", ], shared_libs: [ "libtombstoned_client", ], } rust_defaults { name: "libtombstoned_client_rust_defaults", crate_name: "tombstoned_client", srcs: ["src/lib.rs"], edition: "2021", rustlibs: [ "libcxx", "libthiserror", ], static_libs: [ "libtombstoned_client_wrapper", ], shared_libs: [ "libtombstoned_client", ], } rust_library { name: "libtombstoned_client_rust", defaults: ["libtombstoned_client_rust_defaults"], apex_available: ["com.android.virt"], } rust_test { name: "libtombstoned_client_rust_test", defaults: ["libtombstoned_client_rust_defaults"], require_root: true, test_suites: ["device-tests"], } genrule { name: "libtombstoned_client_rust_bridge_code", tools: ["cxxbridge"], cmd: "$(location cxxbridge) $(in) >> $(out)", srcs: ["src/lib.rs"], out: ["libtombstoned_client_cxx_generated.cc"], } debuggerd/rust/tombstoned_client/src/lib.rs 0 → 100644 +153 −0 Original line number Original line Diff line number Diff line // Copyright 2022, The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Rust wrapper for tombstoned client. pub use ffi::DebuggerdDumpType; use std::fs::File; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use thiserror::Error; /// Error communicating with tombstoned. #[derive(Clone, Debug, Error, Eq, PartialEq)] #[error("Error communicating with tombstoned")] pub struct Error; /// File descriptors for communicating with tombstoned. pub struct TombstonedConnection { /// The socket connection to tombstoned. /// /// This is actually a Unix SOCK_SEQPACKET socket not a file, but the Rust standard library /// doesn't have an appropriate type and it's not really worth bringing in a dependency on `uds` /// or something when all we do is pass it back to C++ or close it. tombstoned_socket: File, /// The file descriptor for text output. pub text_output: Option<File>, /// The file descriptor for proto output. pub proto_output: Option<File>, } impl TombstonedConnection { unsafe fn from_raw_fds( tombstoned_socket: RawFd, text_output_fd: RawFd, proto_output_fd: RawFd, ) -> Self { Self { tombstoned_socket: File::from_raw_fd(tombstoned_socket), text_output: if text_output_fd >= 0 { Some(File::from_raw_fd(text_output_fd)) } else { None }, proto_output: if proto_output_fd >= 0 { Some(File::from_raw_fd(proto_output_fd)) } else { None }, } } /// Connects to tombstoned. pub fn connect(pid: i32, dump_type: DebuggerdDumpType) -> Result<Self, Error> { let mut tombstoned_socket = -1; let mut text_output_fd = -1; let mut proto_output_fd = -1; if ffi::tombstoned_connect_files( pid, &mut tombstoned_socket, &mut text_output_fd, &mut proto_output_fd, dump_type, ) { Ok(unsafe { Self::from_raw_fds(tombstoned_socket, text_output_fd, proto_output_fd) }) } else { Err(Error) } } /// Notifies tombstoned that the dump is complete. pub fn notify_completion(&self) -> Result<(), Error> { if ffi::tombstoned_notify_completion(self.tombstoned_socket.as_raw_fd()) { Ok(()) } else { Err(Error) } } } #[cxx::bridge] mod ffi { /// The type of dump. enum DebuggerdDumpType { /// A native backtrace. #[cxx_name = "kDebuggerdNativeBacktrace"] NativeBacktrace, /// A tombstone. #[cxx_name = "kDebuggerdTombstone"] Tombstone, /// A Java backtrace. #[cxx_name = "kDebuggerdJavaBacktrace"] JavaBacktrace, /// Any intercept. #[cxx_name = "kDebuggerdAnyIntercept"] AnyIntercept, /// A tombstone proto. #[cxx_name = "kDebuggerdTombstoneProto"] TombstoneProto, } unsafe extern "C++" { include!("wrapper.hpp"); type DebuggerdDumpType; fn tombstoned_connect_files( pid: i32, tombstoned_socket: &mut i32, text_output_fd: &mut i32, proto_output_fd: &mut i32, dump_type: DebuggerdDumpType, ) -> bool; fn tombstoned_notify_completion(tombstoned_socket: i32) -> bool; } } #[cfg(test)] mod tests { use super::*; use std::{io::Write, process}; // Verify that we can connect to tombstoned, write something to the file descriptor it returns, // and notify completion, without any errors. #[test] fn test() { let connection = TombstonedConnection::connect(process::id() as i32, DebuggerdDumpType::Tombstone) .expect("Failed to connect to tombstoned."); assert!(connection.proto_output.is_none()); connection .text_output .as_ref() .expect("No text output FD returned.") .write_all(b"test data") .expect("Failed to write to text output FD."); connection .notify_completion() .expect("Failed to notify completion."); } } debuggerd/rust/tombstoned_client/wrapper.cpp 0 → 100644 +38 −0 Original line number Original line Diff line number Diff line /* * Copyright 2022, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "wrapper.hpp" #include <android-base/unique_fd.h> #include "tombstoned/tombstoned.h" using android::base::unique_fd; bool tombstoned_connect_files(pid_t pid, int& tombstoned_socket, int& text_output_fd, int& proto_output_fd, DebuggerdDumpType dump_type) { unique_fd tombstoned_socket_unique, text_output_unique, proto_output_unique; bool result = tombstoned_connect(pid, &tombstoned_socket_unique, &text_output_unique, &proto_output_unique, dump_type); if (result) { tombstoned_socket = tombstoned_socket_unique.release(); text_output_fd = text_output_unique.release(); proto_output_fd = proto_output_unique.release(); } return result; } debuggerd/rust/tombstoned_client/wrapper.hpp 0 → 100644 +23 −0 Original line number Original line Diff line number Diff line /* * Copyright 2022, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <sys/types.h> #include "tombstoned/tombstoned.h" bool tombstoned_connect_files(pid_t pid, int& tombstoned_socket, int& text_output_fd, int& proto_output_fd, DebuggerdDumpType dump_type); Loading
debuggerd/TEST_MAPPING +3 −0 Original line number Original line Diff line number Diff line Loading @@ -2,6 +2,9 @@ "presubmit": [ "presubmit": [ { { "name": "debuggerd_test" "name": "debuggerd_test" }, { "name": "libtombstoned_client_rust_test" } } ] ] } }
debuggerd/rust/tombstoned_client/Android.bp 0 → 100644 +58 −0 Original line number Original line Diff line number Diff line package { default_applicable_licenses: ["Android-Apache-2.0"], } cc_library_static { name: "libtombstoned_client_wrapper", srcs: [ "wrapper.cpp", ], generated_sources: [ "libtombstoned_client_rust_bridge_code" ], header_libs: [ "libbase_headers", "libdebuggerd_common_headers", ], shared_libs: [ "libtombstoned_client", ], } rust_defaults { name: "libtombstoned_client_rust_defaults", crate_name: "tombstoned_client", srcs: ["src/lib.rs"], edition: "2021", rustlibs: [ "libcxx", "libthiserror", ], static_libs: [ "libtombstoned_client_wrapper", ], shared_libs: [ "libtombstoned_client", ], } rust_library { name: "libtombstoned_client_rust", defaults: ["libtombstoned_client_rust_defaults"], apex_available: ["com.android.virt"], } rust_test { name: "libtombstoned_client_rust_test", defaults: ["libtombstoned_client_rust_defaults"], require_root: true, test_suites: ["device-tests"], } genrule { name: "libtombstoned_client_rust_bridge_code", tools: ["cxxbridge"], cmd: "$(location cxxbridge) $(in) >> $(out)", srcs: ["src/lib.rs"], out: ["libtombstoned_client_cxx_generated.cc"], }
debuggerd/rust/tombstoned_client/src/lib.rs 0 → 100644 +153 −0 Original line number Original line Diff line number Diff line // Copyright 2022, The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Rust wrapper for tombstoned client. pub use ffi::DebuggerdDumpType; use std::fs::File; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use thiserror::Error; /// Error communicating with tombstoned. #[derive(Clone, Debug, Error, Eq, PartialEq)] #[error("Error communicating with tombstoned")] pub struct Error; /// File descriptors for communicating with tombstoned. pub struct TombstonedConnection { /// The socket connection to tombstoned. /// /// This is actually a Unix SOCK_SEQPACKET socket not a file, but the Rust standard library /// doesn't have an appropriate type and it's not really worth bringing in a dependency on `uds` /// or something when all we do is pass it back to C++ or close it. tombstoned_socket: File, /// The file descriptor for text output. pub text_output: Option<File>, /// The file descriptor for proto output. pub proto_output: Option<File>, } impl TombstonedConnection { unsafe fn from_raw_fds( tombstoned_socket: RawFd, text_output_fd: RawFd, proto_output_fd: RawFd, ) -> Self { Self { tombstoned_socket: File::from_raw_fd(tombstoned_socket), text_output: if text_output_fd >= 0 { Some(File::from_raw_fd(text_output_fd)) } else { None }, proto_output: if proto_output_fd >= 0 { Some(File::from_raw_fd(proto_output_fd)) } else { None }, } } /// Connects to tombstoned. pub fn connect(pid: i32, dump_type: DebuggerdDumpType) -> Result<Self, Error> { let mut tombstoned_socket = -1; let mut text_output_fd = -1; let mut proto_output_fd = -1; if ffi::tombstoned_connect_files( pid, &mut tombstoned_socket, &mut text_output_fd, &mut proto_output_fd, dump_type, ) { Ok(unsafe { Self::from_raw_fds(tombstoned_socket, text_output_fd, proto_output_fd) }) } else { Err(Error) } } /// Notifies tombstoned that the dump is complete. pub fn notify_completion(&self) -> Result<(), Error> { if ffi::tombstoned_notify_completion(self.tombstoned_socket.as_raw_fd()) { Ok(()) } else { Err(Error) } } } #[cxx::bridge] mod ffi { /// The type of dump. enum DebuggerdDumpType { /// A native backtrace. #[cxx_name = "kDebuggerdNativeBacktrace"] NativeBacktrace, /// A tombstone. #[cxx_name = "kDebuggerdTombstone"] Tombstone, /// A Java backtrace. #[cxx_name = "kDebuggerdJavaBacktrace"] JavaBacktrace, /// Any intercept. #[cxx_name = "kDebuggerdAnyIntercept"] AnyIntercept, /// A tombstone proto. #[cxx_name = "kDebuggerdTombstoneProto"] TombstoneProto, } unsafe extern "C++" { include!("wrapper.hpp"); type DebuggerdDumpType; fn tombstoned_connect_files( pid: i32, tombstoned_socket: &mut i32, text_output_fd: &mut i32, proto_output_fd: &mut i32, dump_type: DebuggerdDumpType, ) -> bool; fn tombstoned_notify_completion(tombstoned_socket: i32) -> bool; } } #[cfg(test)] mod tests { use super::*; use std::{io::Write, process}; // Verify that we can connect to tombstoned, write something to the file descriptor it returns, // and notify completion, without any errors. #[test] fn test() { let connection = TombstonedConnection::connect(process::id() as i32, DebuggerdDumpType::Tombstone) .expect("Failed to connect to tombstoned."); assert!(connection.proto_output.is_none()); connection .text_output .as_ref() .expect("No text output FD returned.") .write_all(b"test data") .expect("Failed to write to text output FD."); connection .notify_completion() .expect("Failed to notify completion."); } }
debuggerd/rust/tombstoned_client/wrapper.cpp 0 → 100644 +38 −0 Original line number Original line Diff line number Diff line /* * Copyright 2022, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "wrapper.hpp" #include <android-base/unique_fd.h> #include "tombstoned/tombstoned.h" using android::base::unique_fd; bool tombstoned_connect_files(pid_t pid, int& tombstoned_socket, int& text_output_fd, int& proto_output_fd, DebuggerdDumpType dump_type) { unique_fd tombstoned_socket_unique, text_output_unique, proto_output_unique; bool result = tombstoned_connect(pid, &tombstoned_socket_unique, &text_output_unique, &proto_output_unique, dump_type); if (result) { tombstoned_socket = tombstoned_socket_unique.release(); text_output_fd = text_output_unique.release(); proto_output_fd = proto_output_unique.release(); } return result; }
debuggerd/rust/tombstoned_client/wrapper.hpp 0 → 100644 +23 −0 Original line number Original line Diff line number Diff line /* * Copyright 2022, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <sys/types.h> #include "tombstoned/tombstoned.h" bool tombstoned_connect_files(pid_t pid, int& tombstoned_socket, int& text_output_fd, int& proto_output_fd, DebuggerdDumpType dump_type);