Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Alice Ryhl and committed by
Greg Kroah-Hartman
c1ea3120 c1093b85

+168
+8
drivers/android/binder/node.rs
··· 178 178 refs: List<NodeRefInfo, { NodeRefInfo::LIST_NODE }>, 179 179 } 180 180 181 + use kernel::bindings::rb_node_layout; 182 + use mem::offset_of; 183 + pub(crate) const NODE_LAYOUT: rb_node_layout = rb_node_layout { 184 + arc_offset: Arc::<Node>::DATA_OFFSET + offset_of!(DTRWrap<Node>, wrapped), 185 + debug_id: offset_of!(Node, debug_id), 186 + ptr: offset_of!(Node, ptr), 187 + }; 188 + 181 189 #[pin_data] 182 190 pub(crate) struct Node { 183 191 pub(crate) debug_id: usize,
+7
drivers/android/binder/process.rs
··· 418 418 } 419 419 } 420 420 421 + use core::mem::offset_of; 422 + use kernel::bindings::rb_process_layout; 423 + pub(crate) const PROCESS_LAYOUT: rb_process_layout = rb_process_layout { 424 + arc_offset: Arc::<Process>::DATA_OFFSET, 425 + task: offset_of!(Process, task), 426 + }; 427 + 421 428 /// A process using binder. 422 429 /// 423 430 /// Strictly speaking, there can be multiple of these per process. There is one for each binder fd
+79
drivers/android/binder/rust_binder.h
··· 20 20 struct dentry *rust_binderfs_create_proc_file(struct inode *nodp, int pid); 21 21 void rust_binderfs_remove_file(struct dentry *dentry); 22 22 23 + /* 24 + * The internal data types in the Rust Binder driver are opaque to C, so we use 25 + * void pointer typedefs for these types. 26 + */ 27 + 28 + typedef void *rust_binder_transaction; 29 + typedef void *rust_binder_process; 30 + typedef void *rust_binder_node; 31 + 32 + struct rb_process_layout { 33 + size_t arc_offset; 34 + size_t task; 35 + }; 36 + 37 + struct rb_transaction_layout { 38 + size_t debug_id; 39 + size_t code; 40 + size_t flags; 41 + size_t from_thread; 42 + size_t to_proc; 43 + size_t target_node; 44 + }; 45 + 46 + struct rb_node_layout { 47 + size_t arc_offset; 48 + size_t debug_id; 49 + size_t ptr; 50 + }; 51 + 52 + struct rust_binder_layout { 53 + struct rb_transaction_layout t; 54 + struct rb_process_layout p; 55 + struct rb_node_layout n; 56 + }; 57 + 58 + extern const struct rust_binder_layout RUST_BINDER_LAYOUT; 59 + 60 + static inline size_t rust_binder_transaction_debug_id(rust_binder_transaction t) 61 + { 62 + return *(size_t *) (t + RUST_BINDER_LAYOUT.t.debug_id); 63 + } 64 + 65 + static inline u32 rust_binder_transaction_code(rust_binder_transaction t) 66 + { 67 + return *(u32 *) (t + RUST_BINDER_LAYOUT.t.code); 68 + } 69 + 70 + static inline u32 rust_binder_transaction_flags(rust_binder_transaction t) 71 + { 72 + return *(u32 *) (t + RUST_BINDER_LAYOUT.t.flags); 73 + } 74 + 75 + // Nullable! 76 + static inline rust_binder_node rust_binder_transaction_target_node(rust_binder_transaction t) 77 + { 78 + void *p = *(void **) (t + RUST_BINDER_LAYOUT.t.target_node); 79 + 80 + if (p) 81 + p = p + RUST_BINDER_LAYOUT.n.arc_offset; 82 + return NULL; 83 + } 84 + 85 + static inline rust_binder_process rust_binder_transaction_to_proc(rust_binder_transaction t) 86 + { 87 + void *p = *(void **) (t + RUST_BINDER_LAYOUT.t.to_proc); 88 + 89 + return p + RUST_BINDER_LAYOUT.p.arc_offset; 90 + } 91 + 92 + static inline struct task_struct *rust_binder_process_task(rust_binder_process t) 93 + { 94 + return *(struct task_struct **) (t + RUST_BINDER_LAYOUT.p.task); 95 + } 96 + 97 + static inline size_t rust_binder_node_debug_id(rust_binder_node t) 98 + { 99 + return *(size_t *) (t + RUST_BINDER_LAYOUT.n.debug_id); 100 + } 101 + 23 102 #endif
+30
drivers/android/binder/rust_binder_events.h
··· 30 30 TP_printk("cmd=0x%x arg=0x%lx", __entry->cmd, __entry->arg) 31 31 ); 32 32 33 + TRACE_EVENT(rust_binder_transaction, 34 + TP_PROTO(bool reply, rust_binder_transaction t, struct task_struct *thread), 35 + TP_ARGS(reply, t, thread), 36 + TP_STRUCT__entry( 37 + __field(int, debug_id) 38 + __field(int, target_node) 39 + __field(int, to_proc) 40 + __field(int, to_thread) 41 + __field(int, reply) 42 + __field(unsigned int, code) 43 + __field(unsigned int, flags) 44 + ), 45 + TP_fast_assign( 46 + rust_binder_process to = rust_binder_transaction_to_proc(t); 47 + rust_binder_node target_node = rust_binder_transaction_target_node(t); 48 + 49 + __entry->debug_id = rust_binder_transaction_debug_id(t); 50 + __entry->target_node = target_node ? rust_binder_node_debug_id(target_node) : 0; 51 + __entry->to_proc = rust_binder_process_task(to)->pid; 52 + __entry->to_thread = thread ? thread->pid : 0; 53 + __entry->reply = reply; 54 + __entry->code = rust_binder_transaction_code(t); 55 + __entry->flags = rust_binder_transaction_flags(t); 56 + ), 57 + TP_printk("transaction=%d dest_node=%d dest_proc=%d dest_thread=%d reply=%d flags=0x%x code=0x%x", 58 + __entry->debug_id, __entry->target_node, 59 + __entry->to_proc, __entry->to_thread, 60 + __entry->reply, __entry->flags, __entry->code) 61 + ); 62 + 33 63 #endif /* _RUST_BINDER_TRACE_H */ 34 64 35 65 /* This part must be outside protection */
+8
drivers/android/binder/rust_binder_main.rs
··· 89 89 license: "GPL", 90 90 } 91 91 92 + use kernel::bindings::rust_binder_layout; 93 + #[no_mangle] 94 + static RUST_BINDER_LAYOUT: rust_binder_layout = rust_binder_layout { 95 + t: transaction::TRANSACTION_LAYOUT, 96 + p: process::PROCESS_LAYOUT, 97 + n: node::NODE_LAYOUT, 98 + }; 99 + 92 100 fn next_debug_id() -> usize { 93 101 static NEXT_DEBUG_ID: AtomicUsize = AtomicUsize::new(0); 94 102
+1
drivers/android/binder/thread.rs
··· 1117 1117 transaction: &DArc<Transaction>, 1118 1118 ) -> bool { 1119 1119 if let Ok(transaction) = &reply { 1120 + crate::trace::trace_transaction(true, transaction, Some(&self.task)); 1120 1121 transaction.set_outstanding(&mut self.process.inner.lock()); 1121 1122 } 1122 1123
+21
drivers/android/binder/trace.rs
··· 2 2 3 3 // Copyright (C) 2025 Google LLC. 4 4 5 + use crate::transaction::Transaction; 6 + 7 + use kernel::bindings::{rust_binder_transaction, task_struct}; 5 8 use kernel::ffi::{c_uint, c_ulong}; 9 + use kernel::task::Task; 6 10 use kernel::tracepoint::declare_trace; 7 11 8 12 declare_trace! { 9 13 unsafe fn rust_binder_ioctl(cmd: c_uint, arg: c_ulong); 14 + unsafe fn rust_binder_transaction(reply: bool, t: rust_binder_transaction, thread: *mut task_struct); 15 + } 16 + 17 + #[inline] 18 + fn raw_transaction(t: &Transaction) -> rust_binder_transaction { 19 + t as *const Transaction as rust_binder_transaction 10 20 } 11 21 12 22 #[inline] 13 23 pub(crate) fn trace_ioctl(cmd: u32, arg: usize) { 14 24 // SAFETY: Always safe to call. 15 25 unsafe { rust_binder_ioctl(cmd, arg as c_ulong) } 26 + } 27 + 28 + #[inline] 29 + pub(crate) fn trace_transaction(reply: bool, t: &Transaction, thread: Option<&Task>) { 30 + let thread = match thread { 31 + Some(thread) => thread.as_ptr(), 32 + None => core::ptr::null_mut(), 33 + }; 34 + // SAFETY: The raw transaction is valid for the duration of this call. The thread pointer is 35 + // valid or null. 36 + unsafe { rust_binder_transaction(reply, raw_transaction(t), thread) } 16 37 }
+14
drivers/android/binder/transaction.rs
··· 24 24 BinderReturnWriter, DArc, DLArc, DTRWrap, DeliverToRead, 25 25 }; 26 26 27 + use core::mem::offset_of; 28 + use kernel::bindings::rb_transaction_layout; 29 + pub(crate) const TRANSACTION_LAYOUT: rb_transaction_layout = rb_transaction_layout { 30 + debug_id: offset_of!(Transaction, debug_id), 31 + code: offset_of!(Transaction, code), 32 + flags: offset_of!(Transaction, flags), 33 + from_thread: offset_of!(Transaction, from), 34 + to_proc: offset_of!(Transaction, to), 35 + target_node: offset_of!(Transaction, target_node), 36 + }; 37 + 27 38 #[pin_data(PinnedDrop)] 28 39 pub(crate) struct Transaction { 29 40 pub(crate) debug_id: usize, ··· 260 249 261 250 if oneway { 262 251 if let Some(target_node) = self.target_node.clone() { 252 + crate::trace::trace_transaction(false, &self, None); 263 253 if process_inner.is_frozen.is_frozen() { 264 254 process_inner.async_recv = true; 265 255 if self.flags & TF_UPDATE_TXN != 0 { ··· 298 286 } 299 287 300 288 let res = if let Some(thread) = self.find_target_thread() { 289 + crate::trace::trace_transaction(false, &self, Some(&thread.task)); 301 290 match thread.push_work(self) { 302 291 PushWorkRes::Ok => Ok(()), 303 292 PushWorkRes::FailedDead(me) => Err((BinderError::new_dead(), me)), 304 293 } 305 294 } else { 295 + crate::trace::trace_transaction(false, &self, None); 306 296 process_inner.push_work(self) 307 297 }; 308 298 drop(process_inner);