summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlice Ryhl <aliceryhl@google.com>2025-12-03 14:48:09 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-12-29 12:14:52 +0100
commitc1ea31205edf2fd748bc6ceb081033bcfa0a869a (patch)
tree8e555b30b1940a6f9485b08837415d1049617ec8
parentc1093b85890693fa2d372468f279854c3624d2b1 (diff)
rust_binder: add binder_transaction tracepoint
This patch adds the binder_transaction tracepoint to Rust Binder. This was chosen as the next tracepoint to add as it is the most complex tracepoint. (And it's also an important tracepoint known to perfetto.) Signed-off-by: Alice Ryhl <aliceryhl@google.com> Link: https://patch.msgid.link/20251203-binder-trace1-v1-2-22d3ffddb44e@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/android/binder/node.rs8
-rw-r--r--drivers/android/binder/process.rs7
-rw-r--r--drivers/android/binder/rust_binder.h79
-rw-r--r--drivers/android/binder/rust_binder_events.h30
-rw-r--r--drivers/android/binder/rust_binder_main.rs8
-rw-r--r--drivers/android/binder/thread.rs1
-rw-r--r--drivers/android/binder/trace.rs21
-rw-r--r--drivers/android/binder/transaction.rs14
8 files changed, 168 insertions, 0 deletions
diff --git a/drivers/android/binder/node.rs b/drivers/android/binder/node.rs
index c26d113ede96..69f757ff7461 100644
--- a/drivers/android/binder/node.rs
+++ b/drivers/android/binder/node.rs
@@ -178,6 +178,14 @@ struct NodeInner {
refs: List<NodeRefInfo, { NodeRefInfo::LIST_NODE }>,
}
+use kernel::bindings::rb_node_layout;
+use mem::offset_of;
+pub(crate) const NODE_LAYOUT: rb_node_layout = rb_node_layout {
+ arc_offset: Arc::<Node>::DATA_OFFSET + offset_of!(DTRWrap<Node>, wrapped),
+ debug_id: offset_of!(Node, debug_id),
+ ptr: offset_of!(Node, ptr),
+};
+
#[pin_data]
pub(crate) struct Node {
pub(crate) debug_id: usize,
diff --git a/drivers/android/binder/process.rs b/drivers/android/binder/process.rs
index 132055b4790f..62b8279b711f 100644
--- a/drivers/android/binder/process.rs
+++ b/drivers/android/binder/process.rs
@@ -418,6 +418,13 @@ impl ProcessNodeRefs {
}
}
+use core::mem::offset_of;
+use kernel::bindings::rb_process_layout;
+pub(crate) const PROCESS_LAYOUT: rb_process_layout = rb_process_layout {
+ arc_offset: Arc::<Process>::DATA_OFFSET,
+ task: offset_of!(Process, task),
+};
+
/// A process using binder.
///
/// Strictly speaking, there can be multiple of these per process. There is one for each binder fd
diff --git a/drivers/android/binder/rust_binder.h b/drivers/android/binder/rust_binder.h
index 31806890ed1a..e68ba7a23c34 100644
--- a/drivers/android/binder/rust_binder.h
+++ b/drivers/android/binder/rust_binder.h
@@ -20,4 +20,83 @@ struct inode;
struct dentry *rust_binderfs_create_proc_file(struct inode *nodp, int pid);
void rust_binderfs_remove_file(struct dentry *dentry);
+/*
+ * The internal data types in the Rust Binder driver are opaque to C, so we use
+ * void pointer typedefs for these types.
+ */
+
+typedef void *rust_binder_transaction;
+typedef void *rust_binder_process;
+typedef void *rust_binder_node;
+
+struct rb_process_layout {
+ size_t arc_offset;
+ size_t task;
+};
+
+struct rb_transaction_layout {
+ size_t debug_id;
+ size_t code;
+ size_t flags;
+ size_t from_thread;
+ size_t to_proc;
+ size_t target_node;
+};
+
+struct rb_node_layout {
+ size_t arc_offset;
+ size_t debug_id;
+ size_t ptr;
+};
+
+struct rust_binder_layout {
+ struct rb_transaction_layout t;
+ struct rb_process_layout p;
+ struct rb_node_layout n;
+};
+
+extern const struct rust_binder_layout RUST_BINDER_LAYOUT;
+
+static inline size_t rust_binder_transaction_debug_id(rust_binder_transaction t)
+{
+ return *(size_t *) (t + RUST_BINDER_LAYOUT.t.debug_id);
+}
+
+static inline u32 rust_binder_transaction_code(rust_binder_transaction t)
+{
+ return *(u32 *) (t + RUST_BINDER_LAYOUT.t.code);
+}
+
+static inline u32 rust_binder_transaction_flags(rust_binder_transaction t)
+{
+ return *(u32 *) (t + RUST_BINDER_LAYOUT.t.flags);
+}
+
+// Nullable!
+static inline rust_binder_node rust_binder_transaction_target_node(rust_binder_transaction t)
+{
+ void *p = *(void **) (t + RUST_BINDER_LAYOUT.t.target_node);
+
+ if (p)
+ p = p + RUST_BINDER_LAYOUT.n.arc_offset;
+ return NULL;
+}
+
+static inline rust_binder_process rust_binder_transaction_to_proc(rust_binder_transaction t)
+{
+ void *p = *(void **) (t + RUST_BINDER_LAYOUT.t.to_proc);
+
+ return p + RUST_BINDER_LAYOUT.p.arc_offset;
+}
+
+static inline struct task_struct *rust_binder_process_task(rust_binder_process t)
+{
+ return *(struct task_struct **) (t + RUST_BINDER_LAYOUT.p.task);
+}
+
+static inline size_t rust_binder_node_debug_id(rust_binder_node t)
+{
+ return *(size_t *) (t + RUST_BINDER_LAYOUT.n.debug_id);
+}
+
#endif
diff --git a/drivers/android/binder/rust_binder_events.h b/drivers/android/binder/rust_binder_events.h
index 2f3efbf9dba6..8ad785c6bd0f 100644
--- a/drivers/android/binder/rust_binder_events.h
+++ b/drivers/android/binder/rust_binder_events.h
@@ -30,6 +30,36 @@ TRACE_EVENT(rust_binder_ioctl,
TP_printk("cmd=0x%x arg=0x%lx", __entry->cmd, __entry->arg)
);
+TRACE_EVENT(rust_binder_transaction,
+ TP_PROTO(bool reply, rust_binder_transaction t, struct task_struct *thread),
+ TP_ARGS(reply, t, thread),
+ TP_STRUCT__entry(
+ __field(int, debug_id)
+ __field(int, target_node)
+ __field(int, to_proc)
+ __field(int, to_thread)
+ __field(int, reply)
+ __field(unsigned int, code)
+ __field(unsigned int, flags)
+ ),
+ TP_fast_assign(
+ rust_binder_process to = rust_binder_transaction_to_proc(t);
+ rust_binder_node target_node = rust_binder_transaction_target_node(t);
+
+ __entry->debug_id = rust_binder_transaction_debug_id(t);
+ __entry->target_node = target_node ? rust_binder_node_debug_id(target_node) : 0;
+ __entry->to_proc = rust_binder_process_task(to)->pid;
+ __entry->to_thread = thread ? thread->pid : 0;
+ __entry->reply = reply;
+ __entry->code = rust_binder_transaction_code(t);
+ __entry->flags = rust_binder_transaction_flags(t);
+ ),
+ TP_printk("transaction=%d dest_node=%d dest_proc=%d dest_thread=%d reply=%d flags=0x%x code=0x%x",
+ __entry->debug_id, __entry->target_node,
+ __entry->to_proc, __entry->to_thread,
+ __entry->reply, __entry->flags, __entry->code)
+);
+
#endif /* _RUST_BINDER_TRACE_H */
/* This part must be outside protection */
diff --git a/drivers/android/binder/rust_binder_main.rs b/drivers/android/binder/rust_binder_main.rs
index c79a9e742240..c04b88936584 100644
--- a/drivers/android/binder/rust_binder_main.rs
+++ b/drivers/android/binder/rust_binder_main.rs
@@ -89,6 +89,14 @@ module! {
license: "GPL",
}
+use kernel::bindings::rust_binder_layout;
+#[no_mangle]
+static RUST_BINDER_LAYOUT: rust_binder_layout = rust_binder_layout {
+ t: transaction::TRANSACTION_LAYOUT,
+ p: process::PROCESS_LAYOUT,
+ n: node::NODE_LAYOUT,
+};
+
fn next_debug_id() -> usize {
static NEXT_DEBUG_ID: AtomicUsize = AtomicUsize::new(0);
diff --git a/drivers/android/binder/thread.rs b/drivers/android/binder/thread.rs
index 1a8e6fdc0dc4..6e8f29e50cac 100644
--- a/drivers/android/binder/thread.rs
+++ b/drivers/android/binder/thread.rs
@@ -1117,6 +1117,7 @@ impl Thread {
transaction: &DArc<Transaction>,
) -> bool {
if let Ok(transaction) = &reply {
+ crate::trace::trace_transaction(true, transaction, Some(&self.task));
transaction.set_outstanding(&mut self.process.inner.lock());
}
diff --git a/drivers/android/binder/trace.rs b/drivers/android/binder/trace.rs
index af0e4392805e..9839901c7151 100644
--- a/drivers/android/binder/trace.rs
+++ b/drivers/android/binder/trace.rs
@@ -2,11 +2,21 @@
// Copyright (C) 2025 Google LLC.
+use crate::transaction::Transaction;
+
+use kernel::bindings::{rust_binder_transaction, task_struct};
use kernel::ffi::{c_uint, c_ulong};
+use kernel::task::Task;
use kernel::tracepoint::declare_trace;
declare_trace! {
unsafe fn rust_binder_ioctl(cmd: c_uint, arg: c_ulong);
+ unsafe fn rust_binder_transaction(reply: bool, t: rust_binder_transaction, thread: *mut task_struct);
+}
+
+#[inline]
+fn raw_transaction(t: &Transaction) -> rust_binder_transaction {
+ t as *const Transaction as rust_binder_transaction
}
#[inline]
@@ -14,3 +24,14 @@ pub(crate) fn trace_ioctl(cmd: u32, arg: usize) {
// SAFETY: Always safe to call.
unsafe { rust_binder_ioctl(cmd, arg as c_ulong) }
}
+
+#[inline]
+pub(crate) fn trace_transaction(reply: bool, t: &Transaction, thread: Option<&Task>) {
+ let thread = match thread {
+ Some(thread) => thread.as_ptr(),
+ None => core::ptr::null_mut(),
+ };
+ // SAFETY: The raw transaction is valid for the duration of this call. The thread pointer is
+ // valid or null.
+ unsafe { rust_binder_transaction(reply, raw_transaction(t), thread) }
+}
diff --git a/drivers/android/binder/transaction.rs b/drivers/android/binder/transaction.rs
index 4bd3c0e417eb..cd8d8202e52d 100644
--- a/drivers/android/binder/transaction.rs
+++ b/drivers/android/binder/transaction.rs
@@ -24,6 +24,17 @@ use crate::{
BinderReturnWriter, DArc, DLArc, DTRWrap, DeliverToRead,
};
+use core::mem::offset_of;
+use kernel::bindings::rb_transaction_layout;
+pub(crate) const TRANSACTION_LAYOUT: rb_transaction_layout = rb_transaction_layout {
+ debug_id: offset_of!(Transaction, debug_id),
+ code: offset_of!(Transaction, code),
+ flags: offset_of!(Transaction, flags),
+ from_thread: offset_of!(Transaction, from),
+ to_proc: offset_of!(Transaction, to),
+ target_node: offset_of!(Transaction, target_node),
+};
+
#[pin_data(PinnedDrop)]
pub(crate) struct Transaction {
pub(crate) debug_id: usize,
@@ -249,6 +260,7 @@ impl Transaction {
if oneway {
if let Some(target_node) = self.target_node.clone() {
+ crate::trace::trace_transaction(false, &self, None);
if process_inner.is_frozen.is_frozen() {
process_inner.async_recv = true;
if self.flags & TF_UPDATE_TXN != 0 {
@@ -286,11 +298,13 @@ impl Transaction {
}
let res = if let Some(thread) = self.find_target_thread() {
+ crate::trace::trace_transaction(false, &self, Some(&thread.task));
match thread.push_work(self) {
PushWorkRes::Ok => Ok(()),
PushWorkRes::FailedDead(me) => Err((BinderError::new_dead(), me)),
}
} else {
+ crate::trace::trace_transaction(false, &self, None);
process_inner.push_work(self)
};
drop(process_inner);