From bf400013472fa0e6f563704bc87a366eaaf92ab3 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Thu, 13 Mar 2025 09:19:56 +0000 Subject: [PATCH] ANDROID: rust_binder: add back tracepoints Tracepoints were removed from the the vendor module version of Rust Binder as it required either fixing b/394605825 or hard-coding the tracepoint declarations as created by bindgen. As we are moving Rust Binder back into common/, this no longer depends on invoking bindgen from the DDK. Thus, revert these changes. Bug: 394605825 Bug: 388786466 Change-Id: I81fe5b2b4c92826c6478606cd78c8fccd8a5c7e4 Signed-off-by: Alice Ryhl --- drivers/android/binder/node.rs | 8 + drivers/android/binder/process.rs | 7 + drivers/android/binder/rust_binder.h | 142 +++++++ drivers/android/binder/rust_binder.rs | 9 + drivers/android/binder/rust_binder_events.c | 6 + drivers/android/binder/rust_binder_events.h | 387 ++++++++++++++++++++ drivers/android/binder/rust_binder_hooks.c | 4 +- drivers/android/binder/rust_binder_hooks.h | 33 ++ drivers/android/binder/thread.rs | 8 + drivers/android/binder/trace.rs | 180 +++++++-- drivers/android/binder/transaction.rs | 11 + rust/bindings/bindings_helper.h | 6 + rust/kernel/sync/arc.rs | 3 + 13 files changed, 776 insertions(+), 28 deletions(-) create mode 100644 drivers/android/binder/rust_binder.h create mode 100644 drivers/android/binder/rust_binder_events.h create mode 100644 drivers/android/binder/rust_binder_hooks.h diff --git a/drivers/android/binder/node.rs b/drivers/android/binder/node.rs index 6d6c22dcb686..383e8b363121 100644 --- a/drivers/android/binder/node.rs +++ b/drivers/android/binder/node.rs @@ -175,6 +175,14 @@ struct NodeInner { refs: List, } +use core::mem::offset_of; +use kernel::bindings::rb_node_layout; +pub(crate) const NODE_LAYOUT: rb_node_layout = rb_node_layout { + arc_offset: Arc::::DATA_OFFSET + offset_of!(DTRWrap, 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 2ac82be4fc26..a1bc503e4a00 100644 --- a/drivers/android/binder/process.rs +++ b/drivers/android/binder/process.rs @@ -383,6 +383,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::::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 new file mode 100644 index 000000000000..8fddca7fc74d --- /dev/null +++ b/drivers/android/binder/rust_binder.h @@ -0,0 +1,142 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_RUST_BINDER_H +#define _LINUX_RUST_BINDER_H + +#include +#include + +/* + * These symbols are exposed by `rust_binderfs.c` and exist here so that Rust + * Binder can call them. + */ +int init_rust_binderfs(void); + +struct dentry; +struct inode; +struct dentry *rust_binderfs_create_proc_file(struct inode *nodp, int pid); +void rust_binderfs_remove_file(struct dentry *dentry); + +typedef void *rust_binder_context; +/** + * struct binder_device - information about a binder device node + * @minor: the minor number used by this device + * @ctx: the Rust Context used by this device, or null for binder-control + * + * This is used as the private data for files directly in binderfs, but not + * files in the binder_logs subdirectory. This struct owns a refcount on `ctx` + * and the entry for `minor` in `binderfs_minors`. For binder-control `ctx` is + * null. + */ +struct binder_device { + int minor; + rust_binder_context ctx; +}; + +/* + * 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_thread; +typedef void *rust_binder_process; +typedef void *rust_binder_node; +typedef void *rust_binder_ref_data; + +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_thread_layout { + size_t arc_offset; + size_t process; + size_t id; +}; + +struct rb_process_layout { + size_t arc_offset; + size_t task; +}; + +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_thread_layout th; + 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 p; +} + +static inline rust_binder_thread rust_binder_transaction_from_thread(rust_binder_transaction t) +{ + void *p = * (void **) (t + RUST_BINDER_LAYOUT.t.from_thread); + return p + RUST_BINDER_LAYOUT.th.arc_offset; +} + +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 rust_binder_process rust_binder_thread_proc(rust_binder_thread t) +{ + void *p = * (void **) (t + RUST_BINDER_LAYOUT.th.process); + return p + RUST_BINDER_LAYOUT.p.arc_offset; +} + +static inline s32 rust_binder_thread_id(rust_binder_thread t) +{ + return * (s32 *) (t + RUST_BINDER_LAYOUT.th.id); +} + +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); +} + +static inline binder_uintptr_t rust_binder_node_ptr(rust_binder_node t) +{ + return * (binder_uintptr_t *) (t + RUST_BINDER_LAYOUT.n.ptr); +} + +#endif diff --git a/drivers/android/binder/rust_binder.rs b/drivers/android/binder/rust_binder.rs index 1bf09bd80395..d95d0f87e402 100644 --- a/drivers/android/binder/rust_binder.rs +++ b/drivers/android/binder/rust_binder.rs @@ -83,6 +83,15 @@ 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, + th: thread::THREAD_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/rust_binder_events.c b/drivers/android/binder/rust_binder_events.c index 654abea8ccc0..eb8db908e164 100644 --- a/drivers/android/binder/rust_binder_events.c +++ b/drivers/android/binder/rust_binder_events.c @@ -6,6 +6,8 @@ * Copyright 2024 Google LLC */ +#include "rust_binder.h" + const char * const binder_command_strings[] = { "BC_TRANSACTION", "BC_REPLY", @@ -51,3 +53,7 @@ const char * const binder_return_strings[] = { "BR_ONEWAY_SPAM_SUSPECT", "BR_TRANSACTION_PENDING_FROZEN" }; + +#define CREATE_TRACE_POINTS +#define CREATE_RUST_TRACE_POINTS +#include "rust_binder_events.h" diff --git a/drivers/android/binder/rust_binder_events.h b/drivers/android/binder/rust_binder_events.h new file mode 100644 index 000000000000..87e088101fae --- /dev/null +++ b/drivers/android/binder/rust_binder_events.h @@ -0,0 +1,387 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024 Google, Inc. + */ + +#undef TRACE_SYSTEM +#undef TRACE_INCLUDE_FILE +#undef TRACE_INCLUDE_PATH +#define TRACE_SYSTEM rust_binder +#define TRACE_INCLUDE_FILE rust_binder_events +#define TRACE_INCLUDE_PATH ../drivers/android/binder + +#if !defined(_RUST_BINDER_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _RUST_BINDER_TRACE_H + +#include + +TRACE_EVENT(rust_binder_ioctl, + TP_PROTO(unsigned int cmd, unsigned long arg), + TP_ARGS(cmd, arg), + + TP_STRUCT__entry( + __field(unsigned int, cmd) + __field(unsigned long, arg) + ), + TP_fast_assign( + __entry->cmd = cmd; + __entry->arg = arg; + ), + TP_printk("cmd=0x%x arg=0x%lx", __entry->cmd, __entry->arg) +); + +DECLARE_EVENT_CLASS(rust_binder_function_return_class, + TP_PROTO(int ret), + TP_ARGS(ret), + TP_STRUCT__entry( + __field(int, ret) + ), + TP_fast_assign( + __entry->ret = ret; + ), + TP_printk("ret=%d", __entry->ret) +); + +#define DEFINE_RBINDER_FUNCTION_RETURN_EVENT(name) \ +DEFINE_EVENT(rust_binder_function_return_class, name, \ + TP_PROTO(int ret), \ + TP_ARGS(ret)) + +DEFINE_RBINDER_FUNCTION_RETURN_EVENT(rust_binder_ioctl_done); +DEFINE_RBINDER_FUNCTION_RETURN_EVENT(rust_binder_read_done); +DEFINE_RBINDER_FUNCTION_RETURN_EVENT(rust_binder_write_done); + +TRACE_EVENT(rust_binder_set_priority, + TP_PROTO(struct task_struct *thread, int desired_prio, int new_prio), + TP_ARGS(thread, desired_prio, new_prio), + + TP_STRUCT__entry( + __field(int, proc) + __field(int, thread) + __field(unsigned int, old_prio) + __field(unsigned int, new_prio) + __field(unsigned int, desired_prio) + ), + TP_fast_assign( + __entry->proc = thread->tgid; + __entry->thread = thread->pid; + __entry->old_prio = thread->normal_prio; + __entry->new_prio = new_prio; + __entry->desired_prio = desired_prio; + ), + TP_printk("proc=%d thread=%d old=%d => new=%d desired=%d", + __entry->proc, __entry->thread, __entry->old_prio, + __entry->new_prio, __entry->desired_prio) +); + +TRACE_EVENT(rust_binder_wait_for_work, + TP_PROTO(bool proc_work, bool transaction_stack, bool thread_todo), + TP_ARGS(proc_work, transaction_stack, thread_todo), + + TP_STRUCT__entry( + __field(bool, proc_work) + __field(bool, transaction_stack) + __field(bool, thread_todo) + ), + TP_fast_assign( + __entry->proc_work = proc_work; + __entry->transaction_stack = transaction_stack; + __entry->thread_todo = thread_todo; + ), + TP_printk("proc_work=%d transaction_stack=%d thread_todo=%d", + __entry->proc_work, __entry->transaction_stack, + __entry->thread_todo) +); + +TRACE_EVENT(rust_binder_transaction, + TP_PROTO(bool reply, rust_binder_transaction t), + TP_ARGS(reply, t), + TP_STRUCT__entry( + __field(int, debug_id) + __field(int, target_node) + __field(int, from_proc) + __field(int, to_proc) + __field(int, reply) + __field(unsigned int, code) + __field(unsigned int, flags) + ), + TP_fast_assign( + rust_binder_thread from_thread = rust_binder_transaction_from_thread(t); + rust_binder_process from = rust_binder_thread_proc(from_thread); + 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->from_proc = rust_binder_process_task(from)->pid; + __entry->to_proc = rust_binder_process_task(to)->pid; + __entry->reply = reply; + __entry->code = rust_binder_transaction_code(t); + __entry->flags = rust_binder_transaction_flags(t); + ), + TP_printk("transaction=%d target_node=%d dest_proc=%d from_proc=%d reply=%d flags=0x%x code=0x%x", + __entry->debug_id, __entry->target_node, __entry->to_proc, + __entry->from_proc, __entry->reply, __entry->flags, + __entry->code) +); + +TRACE_EVENT(rust_binder_transaction_thread_selected, + TP_PROTO(rust_binder_transaction t, rust_binder_thread thread), + TP_ARGS(t, thread), + TP_STRUCT__entry( + __field(int, debug_id) + __field(int, to_thread) + ), + TP_fast_assign( + __entry->debug_id = rust_binder_transaction_debug_id(t); + __entry->to_thread = rust_binder_thread_id(thread); + ), + TP_printk("transaction=%d thread=%d", __entry->debug_id, __entry->to_thread) +); + +TRACE_EVENT(rust_binder_transaction_received, + TP_PROTO(rust_binder_transaction t), + TP_ARGS(t), + TP_STRUCT__entry( + __field(int, debug_id) + ), + TP_fast_assign( + __entry->debug_id = rust_binder_transaction_debug_id(t); + ), + TP_printk("transaction=%d", __entry->debug_id) +); + +TRACE_EVENT(rust_binder_transaction_node_send, + TP_PROTO(int t_debug_id, rust_binder_node node, + const struct flat_binder_object *original, + const struct flat_binder_object *translated), + TP_ARGS(t_debug_id, node, original, translated), + + TP_STRUCT__entry( + __field(int, debug_id) + __field(int, node_debug_id) + __field(binder_uintptr_t, node_ptr) + __field(int, types) + __field(int, original_handle) + __field(int, translated_handle) + ), + TP_fast_assign( + int orig_is_handle = original->hdr.type == BINDER_TYPE_HANDLE || original->hdr.type == BINDER_TYPE_WEAK_HANDLE; + int orig_is_strong = original->hdr.type == BINDER_TYPE_HANDLE || original->hdr.type == BINDER_TYPE_BINDER; + int tran_is_handle = translated->hdr.type == BINDER_TYPE_HANDLE || translated->hdr.type == BINDER_TYPE_WEAK_HANDLE; + int tran_is_strong = translated->hdr.type == BINDER_TYPE_HANDLE || translated->hdr.type == BINDER_TYPE_BINDER; + + __entry->debug_id = t_debug_id; + __entry->node_debug_id = rust_binder_node_debug_id(node); + __entry->node_ptr = rust_binder_node_debug_id(node); + __entry->types = + (orig_is_handle << 0) | + (tran_is_handle << 1) | + (orig_is_strong << 2) | + (tran_is_strong << 3); + __entry->original_handle = orig_is_handle ? original->handle : 0; + __entry->translated_handle = tran_is_handle ? original->handle : 0; + ), + TP_printk("transaction=%d node=%d ptr=0x%016llx: %s%s [%d] ==> %s%s [%d]", + __entry->debug_id, __entry->node_debug_id, + (u64)__entry->node_ptr, + (__entry->types & (1<<2)) ? "" : "weak ", + (__entry->types & (1<<0)) ? "handle" : "binder", + __entry->original_handle, + (__entry->types & (1<<3)) ? "" : "weak ", + (__entry->types & (1<<1)) ? "handle" : "binder", + __entry->translated_handle) +); + +TRACE_EVENT(rust_binder_transaction_fd_send, + TP_PROTO(int t_debug_id, int fd, size_t offset), + TP_ARGS(t_debug_id, fd, offset), + + TP_STRUCT__entry( + __field(int, debug_id) + __field(int, fd) + __field(size_t, offset) + ), + TP_fast_assign( + __entry->debug_id = t_debug_id; + __entry->fd = fd; + __entry->offset = offset; + ), + TP_printk("transaction=%d src_fd=%d offset=%zu", + __entry->debug_id, __entry->fd, __entry->offset) +); + +TRACE_EVENT(rust_binder_transaction_fd_recv, + TP_PROTO(int t_debug_id, int fd, size_t offset), + TP_ARGS(t_debug_id, fd, offset), + + TP_STRUCT__entry( + __field(int, debug_id) + __field(int, fd) + __field(size_t, offset) + ), + TP_fast_assign( + __entry->debug_id = t_debug_id; + __entry->fd = fd; + __entry->offset = offset; + ), + TP_printk("transaction=%d dest_fd=%d offset=%zu", + __entry->debug_id, __entry->fd, __entry->offset) +); + +TRACE_EVENT(rust_binder_transaction_alloc_buf, + TP_PROTO(int debug_id, const struct binder_transaction_data_sg *data), + TP_ARGS(debug_id, data), + + TP_STRUCT__entry( + __field(int, debug_id) + __field(size_t, data_size) + __field(size_t, offsets_size) + __field(size_t, extra_buffers_size) + ), + TP_fast_assign( + __entry->debug_id = debug_id; + __entry->data_size = data->transaction_data.data_size; + __entry->offsets_size = data->transaction_data.offsets_size; + __entry->extra_buffers_size = data->buffers_size; + ), + TP_printk("transaction=%d data_size=%zd offsets_size=%zd extra_buffers_size=%zd", + __entry->debug_id, __entry->data_size, __entry->offsets_size, + __entry->extra_buffers_size) +); + +DECLARE_EVENT_CLASS(rust_binder_buffer_release_class, + TP_PROTO(int debug_id), + TP_ARGS(debug_id), + TP_STRUCT__entry( + __field(int, debug_id) + ), + TP_fast_assign( + __entry->debug_id = debug_id; + ), + TP_printk("transaction=%d", __entry->debug_id) +); + +DEFINE_EVENT(rust_binder_buffer_release_class, rust_binder_transaction_buffer_release, + TP_PROTO(int debug_id), + TP_ARGS(debug_id)); + +DEFINE_EVENT(rust_binder_buffer_release_class, rust_binder_transaction_failed_buffer_release, + TP_PROTO(int debug_id), + TP_ARGS(debug_id)); + +DEFINE_EVENT(rust_binder_buffer_release_class, rust_binder_transaction_update_buffer_release, + TP_PROTO(int debug_id), + TP_ARGS(debug_id)); + +TRACE_EVENT(rust_binder_update_page_range, + TP_PROTO(int pid, bool allocate, size_t start, size_t end), + TP_ARGS(pid, allocate, start, end), + TP_STRUCT__entry( + __field(int, proc) + __field(bool, allocate) + __field(size_t, offset) + __field(size_t, size) + ), + TP_fast_assign( + __entry->proc = pid; + __entry->allocate = allocate; + __entry->offset = start; + __entry->size = end - start; + ), + TP_printk("proc=%d allocate=%d offset=%zu size=%zu", + __entry->proc, __entry->allocate, + __entry->offset, __entry->size) +); + +DECLARE_EVENT_CLASS(rust_binder_lru_page_class, + TP_PROTO(int pid, size_t page_index), + TP_ARGS(pid, page_index), + TP_STRUCT__entry( + __field(int, proc) + __field(size_t, page_index) + ), + TP_fast_assign( + __entry->proc = pid; + __entry->page_index = page_index; + ), + TP_printk("proc=%d page_index=%zu", + __entry->proc, __entry->page_index) +); + +DEFINE_EVENT(rust_binder_lru_page_class, rust_binder_alloc_lru_start, + TP_PROTO(int pid, size_t page_index), + TP_ARGS(pid, page_index)); + +DEFINE_EVENT(rust_binder_lru_page_class, rust_binder_alloc_lru_end, + TP_PROTO(int pid, size_t page_index), + TP_ARGS(pid, page_index)); + +DEFINE_EVENT(rust_binder_lru_page_class, rust_binder_free_lru_start, + TP_PROTO(int pid, size_t page_index), + TP_ARGS(pid, page_index)); + +DEFINE_EVENT(rust_binder_lru_page_class, rust_binder_free_lru_end, + TP_PROTO(int pid, size_t page_index), + TP_ARGS(pid, page_index)); + +DEFINE_EVENT(rust_binder_lru_page_class, rust_binder_alloc_page_start, + TP_PROTO(int pid, size_t page_index), + TP_ARGS(pid, page_index)); + +DEFINE_EVENT(rust_binder_lru_page_class, rust_binder_alloc_page_end, + TP_PROTO(int pid, size_t page_index), + TP_ARGS(pid, page_index)); + +DEFINE_EVENT(rust_binder_lru_page_class, rust_binder_unmap_user_start, + TP_PROTO(int pid, size_t page_index), + TP_ARGS(pid, page_index)); + +DEFINE_EVENT(rust_binder_lru_page_class, rust_binder_unmap_user_end, + TP_PROTO(int pid, size_t page_index), + TP_ARGS(pid, page_index)); + +DEFINE_EVENT(rust_binder_lru_page_class, rust_binder_unmap_kernel_start, + TP_PROTO(int pid, size_t page_index), + TP_ARGS(pid, page_index)); + +DEFINE_EVENT(rust_binder_lru_page_class, rust_binder_unmap_kernel_end, + TP_PROTO(int pid, size_t page_index), + TP_ARGS(pid, page_index)); + +TRACE_EVENT(rust_binder_command, + TP_PROTO(uint32_t cmd), + TP_ARGS(cmd), + TP_STRUCT__entry( + __field(uint32_t, cmd) + ), + TP_fast_assign( + __entry->cmd = cmd; + ), + TP_printk("cmd=0x%x %s", + __entry->cmd, + _IOC_NR(__entry->cmd) < ARRAY_SIZE(binder_command_strings) ? + binder_command_strings[_IOC_NR(__entry->cmd)] : + "unknown") +); + +TRACE_EVENT(rust_binder_return, + TP_PROTO(uint32_t ret), + TP_ARGS(ret), + TP_STRUCT__entry( + __field(uint32_t, ret) + ), + TP_fast_assign( + __entry->ret = ret; + ), + TP_printk("ret=0x%x %s", + __entry->ret, + _IOC_NR(__entry->ret) < ARRAY_SIZE(binder_return_strings) ? + binder_return_strings[_IOC_NR(__entry->ret)] : + "unknown") +); + +#endif /* _RUST_BINDER_TRACE_H */ + +/* This part must be outside protection */ +#include diff --git a/drivers/android/binder/rust_binder_hooks.c b/drivers/android/binder/rust_binder_hooks.c index 5b543c67a262..4dda768d7df3 100644 --- a/drivers/android/binder/rust_binder_hooks.c +++ b/drivers/android/binder/rust_binder_hooks.c @@ -6,14 +6,14 @@ * Copyright 2024 Google LLC */ -#include +#include "rust_binder.h" #define CREATE_TRACE_POINTS #define CREATE_RUST_TRACE_POINTS #include #include -#include +#include "rust_binder_hooks.h" /* * Export tracepoints that act as a bare tracehook (ie: have no trace event diff --git a/drivers/android/binder/rust_binder_hooks.h b/drivers/android/binder/rust_binder_hooks.h new file mode 100644 index 000000000000..a62eeeac11a4 --- /dev/null +++ b/drivers/android/binder/rust_binder_hooks.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024 Google, Inc. + */ + +#undef TRACE_SYSTEM +#undef TRACE_INCLUDE_FILE +#undef TRACE_INCLUDE_PATH +#define TRACE_SYSTEM rust_binder +#define TRACE_INCLUDE_FILE rust_binder_hooks +#define TRACE_INCLUDE_PATH ../drivers/android/binder + +#if !defined(_RUST_BINDER_HOOK_H) || defined(TRACE_HEADER_MULTI_READ) +#define _RUST_BINDER_HOOK_H + +#include + +/* + * Following tracepoints are not exported in tracefs and provide a + * mechanism for vendor modules to hook and extend functionality + */ + +DECLARE_HOOK(android_vh_rust_binder_set_priority, + TP_PROTO(rust_binder_transaction t, struct task_struct *task), + TP_ARGS(t, task)); +DECLARE_HOOK(android_vh_rust_binder_restore_priority, + TP_PROTO(struct task_struct *task), + TP_ARGS(task)); + +#endif /* _RUST_BINDER_HOOK_H */ + +/* This part must be outside protection */ +#include diff --git a/drivers/android/binder/thread.rs b/drivers/android/binder/thread.rs index 3514543ff660..bcf54b6b48a8 100644 --- a/drivers/android/binder/thread.rs +++ b/drivers/android/binder/thread.rs @@ -411,6 +411,14 @@ pub(crate) struct ThreadPrioState { pub(crate) next: BinderPriority, } +use core::mem::offset_of; +use kernel::bindings::rb_thread_layout; +pub(crate) const THREAD_LAYOUT: rb_thread_layout = rb_thread_layout { + arc_offset: Arc::::DATA_OFFSET, + process: offset_of!(Thread, process), + id: offset_of!(Thread, id), +}; + /// This represents a thread that's used with binder. #[pin_data] pub(crate) struct Thread { diff --git a/drivers/android/binder/trace.rs b/drivers/android/binder/trace.rs index 6ded53d21c4f..a6d606952df1 100644 --- a/drivers/android/binder/trace.rs +++ b/drivers/android/binder/trace.rs @@ -2,88 +2,210 @@ // Copyright (C) 2024 Google LLC. -#![allow(unused_variables)] -#![allow(unused_imports)] - use crate::{defs::BinderTransactionDataSg, node::Node, thread::Thread, transaction::Transaction}; +use kernel::bindings::{ + binder_transaction_data_sg, flat_binder_object, rust_binder_node, rust_binder_thread, + rust_binder_transaction, task_struct, +}; use kernel::error::Result; use kernel::task::{Pid, Task}; use kernel::tracepoint::declare_trace; -use kernel::uapi::flat_binder_object; +use kernel::uapi; use core::ffi::{c_int, c_uint, c_ulong}; -#[inline] -pub(crate) fn trace_ioctl(cmd: u32, arg: usize) {} +declare_trace! { + unsafe fn rust_binder_ioctl(cmd: c_uint, arg: c_ulong); + unsafe fn rust_binder_ioctl_done(ret: c_int); + unsafe fn rust_binder_read_done(ret: c_int); + unsafe fn rust_binder_write_done(ret: c_int); + unsafe fn rust_binder_set_priority(thread: *mut task_struct, desired_prio: c_int, new_prio: c_int); + unsafe fn android_vh_rust_binder_set_priority(t: rust_binder_transaction, task: *mut task_struct); + unsafe fn android_vh_rust_binder_restore_priority(task: *mut task_struct); + unsafe fn rust_binder_wait_for_work(proc_work: bool, transaction_stack: bool, thread_todo: bool); + unsafe fn rust_binder_transaction(reply: bool, t: rust_binder_transaction); + unsafe fn rust_binder_transaction_received(t: rust_binder_transaction); + unsafe fn rust_binder_transaction_thread_selected(t: rust_binder_transaction, thread: rust_binder_thread); + unsafe fn rust_binder_transaction_node_send(t_debug_id: c_int, n: rust_binder_node, + orig: *const flat_binder_object, + trans: *const flat_binder_object); + unsafe fn rust_binder_transaction_fd_send(t_debug_id: c_int, fd: c_int, offset: usize); + unsafe fn rust_binder_transaction_fd_recv(t_debug_id: c_int, fd: c_int, offset: usize); + unsafe fn rust_binder_transaction_alloc_buf(debug_id: c_int, data: *const binder_transaction_data_sg); + unsafe fn rust_binder_transaction_buffer_release(debug_id: c_int); + unsafe fn rust_binder_transaction_failed_buffer_release(debug_id: c_int); + unsafe fn rust_binder_transaction_update_buffer_release(debug_id: c_int); + unsafe fn rust_binder_update_page_range(pid: c_int, allocate: bool, start: usize, end: usize); + unsafe fn rust_binder_alloc_lru_start(pid: c_int, page_index: usize); + unsafe fn rust_binder_alloc_lru_end(pid: c_int, page_index: usize); + unsafe fn rust_binder_free_lru_start(pid: c_int, page_index: usize); + unsafe fn rust_binder_free_lru_end(pid: c_int, page_index: usize); + unsafe fn rust_binder_alloc_page_start(pid: c_int, page_index: usize); + unsafe fn rust_binder_alloc_page_end(pid: c_int, page_index: usize); + unsafe fn rust_binder_unmap_user_start(pid: c_int, page_index: usize); + unsafe fn rust_binder_unmap_user_end(pid: c_int, page_index: usize); + unsafe fn rust_binder_unmap_kernel_start(pid: c_int, page_index: usize); + unsafe fn rust_binder_unmap_kernel_end(pid: c_int, page_index: usize); + unsafe fn rust_binder_command(cmd: u32); + unsafe fn rust_binder_return(ret: u32); +} #[inline] -pub(crate) fn trace_ioctl_done(ret: Result) {} +fn raw_transaction(t: &Transaction) -> rust_binder_transaction { + t as *const Transaction as rust_binder_transaction +} #[inline] -pub(crate) fn trace_read_done(ret: Result) {} +fn raw_thread(t: &Thread) -> rust_binder_thread { + t as *const Thread as rust_binder_thread +} #[inline] -pub(crate) fn trace_write_done(ret: Result) {} +fn raw_node(n: &Node) -> rust_binder_node { + n as *const Node as rust_binder_node +} #[inline] -pub(crate) fn trace_set_priority(thread: &Task, desired_prio: c_int, new_prio: c_int) {} +fn to_errno(ret: Result) -> i32 { + match ret { + Ok(()) => 0, + Err(err) => err.to_errno(), + } +} #[inline] -pub(crate) fn vh_set_priority(t: &Transaction, task: &Task) {} +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 vh_restore_priority(task: &Task) {} +pub(crate) fn trace_ioctl_done(ret: Result) { + // SAFETY: Always safe to call. + unsafe { rust_binder_ioctl_done(to_errno(ret)) } +} #[inline] -pub(crate) fn trace_wait_for_work(proc_work: bool, transaction_stack: bool, thread_todo: bool) {} +pub(crate) fn trace_read_done(ret: Result) { + // SAFETY: Always safe to call. + unsafe { rust_binder_read_done(to_errno(ret)) } +} #[inline] -pub(crate) fn trace_transaction(reply: bool, t: &Transaction) {} +pub(crate) fn trace_write_done(ret: Result) { + // SAFETY: Always safe to call. + unsafe { rust_binder_write_done(to_errno(ret)) } +} #[inline] -pub(crate) fn trace_transaction_received(t: &Transaction) {} +pub(crate) fn trace_set_priority(thread: &Task, desired_prio: c_int, new_prio: c_int) { + // SAFETY: The pointer to the task is valid for the duration of this call. + unsafe { rust_binder_set_priority(thread.as_ptr(), desired_prio, new_prio) } +} #[inline] -pub(crate) fn trace_transaction_thread_selected(t: &Transaction, th: &Thread) {} +pub(crate) fn vh_set_priority(t: &Transaction, task: &Task) { + // SAFETY: The pointers to `t` and `task` are valid. + unsafe { android_vh_rust_binder_set_priority(raw_transaction(t), task.as_ptr()) } +} + +#[inline] +pub(crate) fn vh_restore_priority(task: &Task) { + // SAFETY: The pointer to `task` is valid. + unsafe { android_vh_rust_binder_restore_priority(task.as_ptr()) } +} + +#[inline] +pub(crate) fn trace_wait_for_work(proc_work: bool, transaction_stack: bool, thread_todo: bool) { + // SAFETY: Always safe to call. + unsafe { rust_binder_wait_for_work(proc_work, transaction_stack, thread_todo) } +} + +#[inline] +pub(crate) fn trace_transaction(reply: bool, t: &Transaction) { + // SAFETY: The raw transaction is valid for the duration of this call. + unsafe { rust_binder_transaction(reply, raw_transaction(t)) } +} + +#[inline] +pub(crate) fn trace_transaction_received(t: &Transaction) { + // SAFETY: The raw transaction is valid for the duration of this call. + unsafe { rust_binder_transaction_received(raw_transaction(t)) } +} + +#[inline] +pub(crate) fn trace_transaction_thread_selected(t: &Transaction, th: &Thread) { + // SAFETY: The raw transaction is valid for the duration of this call. + unsafe { rust_binder_transaction_thread_selected(raw_transaction(t), raw_thread(th)) } +} #[inline] pub(crate) fn trace_transaction_node_send( t_debug_id: usize, n: &Node, - orig: &flat_binder_object, - trans: &flat_binder_object, + orig: &uapi::flat_binder_object, + trans: &uapi::flat_binder_object, ) { + // CAST: Types are identical. + let orig = orig as *const uapi::flat_binder_object as *const flat_binder_object; + // CAST: Types are identical. + let trans = trans as *const uapi::flat_binder_object as *const flat_binder_object; + + // SAFETY: The pointers are valid for the duration of this call. + unsafe { rust_binder_transaction_node_send(t_debug_id as c_int, raw_node(n), orig, trans) } } #[inline] -pub(crate) fn trace_transaction_fd_send(t_debug_id: usize, fd: u32, offset: usize) {} +pub(crate) fn trace_transaction_fd_send(t_debug_id: usize, fd: u32, offset: usize) { + // SAFETY: This function is always safe to call. + unsafe { rust_binder_transaction_fd_send(t_debug_id as c_int, fd as c_int, offset) } +} #[inline] -pub(crate) fn trace_transaction_fd_recv(t_debug_id: usize, fd: u32, offset: usize) {} +pub(crate) fn trace_transaction_fd_recv(t_debug_id: usize, fd: u32, offset: usize) { + // SAFETY: This function is always safe to call. + unsafe { rust_binder_transaction_fd_recv(t_debug_id as c_int, fd as c_int, offset) } +} #[inline] pub(crate) fn trace_transaction_alloc_buf(debug_id: usize, data: &BinderTransactionDataSg) { let data = data as *const BinderTransactionDataSg; + // SAFETY: The `data` pointer is valid. + unsafe { rust_binder_transaction_alloc_buf(debug_id as c_int, data.cast()) } } #[inline] -pub(crate) fn trace_transaction_buffer_release(debug_id: usize) {} +pub(crate) fn trace_transaction_buffer_release(debug_id: usize) { + // SAFETY: Always safe to call. + unsafe { rust_binder_transaction_buffer_release(debug_id as c_int) } +} #[inline] -pub(crate) fn trace_transaction_failed_buffer_release(debug_id: usize) {} +pub(crate) fn trace_transaction_failed_buffer_release(debug_id: usize) { + // SAFETY: Always safe to call. + unsafe { rust_binder_transaction_failed_buffer_release(debug_id as c_int) } +} #[inline] -pub(crate) fn trace_transaction_update_buffer_release(debug_id: usize) {} +pub(crate) fn trace_transaction_update_buffer_release(debug_id: usize) { + // SAFETY: Always safe to call. + unsafe { rust_binder_transaction_update_buffer_release(debug_id as c_int) } +} #[inline] -pub(crate) fn trace_update_page_range(pid: Pid, allocate: bool, start: usize, end: usize) {} +pub(crate) fn trace_update_page_range(pid: Pid, allocate: bool, start: usize, end: usize) { + // SAFETY: Always safe to call. + unsafe { rust_binder_update_page_range(pid as c_int, allocate, start, end) } +} macro_rules! define_wrapper_lru_page_class { ($(fn $name:ident;)*) => {$( kernel::macros::paste! { #[inline] pub(crate) fn [< trace_ $name >](pid: Pid, page_index: usize) { + // SAFETY: Always safe to call. + unsafe { [< rust_binder_ $name >](pid as c_int, page_index) } } } )*} @@ -103,7 +225,13 @@ define_wrapper_lru_page_class! { } #[inline] -pub(crate) fn trace_command(cmd: u32) {} +pub(crate) fn trace_command(cmd: u32) { + // SAFETY: Trivially safe to call with primitive u32. + unsafe { rust_binder_command(cmd) } +} #[inline] -pub(crate) fn trace_return(ret: u32) {} +pub(crate) fn trace_return(ret: u32) { + // SAFETY: Trivially safe to call with primitive u32. + unsafe { rust_binder_return(ret) } +} diff --git a/drivers/android/binder/transaction.rs b/drivers/android/binder/transaction.rs index 4ae97d8ad13e..6cde1ec425bc 100644 --- a/drivers/android/binder/transaction.rs +++ b/drivers/android/binder/transaction.rs @@ -25,6 +25,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, diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 4c9ddf06e6df..043f40927fdf 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -58,3 +58,9 @@ const blk_features_t RUST_CONST_HELPER_BLK_FEAT_ROTATIONAL = BLK_FEAT_ROTATIONAL const size_t RUST_CONST_HELPER_ASHMEM_NAME_PREFIX_LEN = ASHMEM_NAME_PREFIX_LEN; const size_t RUST_CONST_HELPER_ASHMEM_FULL_NAME_LEN = ASHMEM_FULL_NAME_LEN; #endif + +#if IS_ENABLED(CONFIG_ANDROID_BINDER_IPC_RUST) +#include "../../drivers/android/binder/rust_binder.h" +#include "../../drivers/android/binder/rust_binder_hooks.h" +#include "../../drivers/android/binder/rust_binder_events.h" +#endif diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index fa4509406ee9..55933f8a82ab 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -206,6 +206,9 @@ impl Arc { // `Arc` object. Ok(unsafe { Self::from_inner(KBox::leak(inner).into()) }) } + + /// The offset that the value is stored at. + pub const DATA_OFFSET: usize = core::mem::offset_of!(ArcInner, data); } impl Arc {