Merge "Add Rust wrapper for tombstoned client using cxx."

This commit is contained in:
Treehugger Robot 2022-04-04 22:38:40 +00:00 committed by Gerrit Code Review
commit fad82b6c15
5 changed files with 275 additions and 0 deletions

View File

@ -2,6 +2,9 @@
"presubmit": [
{
"name": "debuggerd_test"
},
{
"name": "libtombstoned_client_rust_test"
}
]
}

View File

@ -0,0 +1,58 @@
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"],
}

View File

@ -0,0 +1,153 @@
// 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.");
}
}

View File

@ -0,0 +1,38 @@
/*
* 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;
}

View File

@ -0,0 +1,23 @@
/*
* 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);