| /* SPDX-License-Identifier: GPL-2.0 */ | |
| #ifndef _LINUX_BINDER_INTERNAL_H | |
| #define _LINUX_BINDER_INTERNAL_H | |
| #include <linux/fs.h> | |
| #include <linux/list.h> | |
| #include <linux/miscdevice.h> | |
| #include <linux/mutex.h> | |
| #include <linux/refcount.h> | |
| #include <linux/stddef.h> | |
| #include <linux/types.h> | |
| #include <linux/uidgid.h> | |
| #include <uapi/linux/android/binderfs.h> | |
| #include "binder_alloc.h" | |
| #include "dbitmap.h" | |
| struct binder_context { | |
| struct binder_node *binder_context_mgr_node; | |
| struct mutex context_mgr_node_lock; | |
| kuid_t binder_context_mgr_uid; | |
| const char *name; | |
| }; | |
| /** | |
| * struct binder_device - information about a binder device node | |
| * @hlist: list of binder devices | |
| * @miscdev: information about a binder character device node | |
| * @context: binder context information | |
| * @binderfs_inode: This is the inode of the root dentry of the super block | |
| * belonging to a binderfs mount. | |
| */ | |
| struct binder_device { | |
| struct hlist_node hlist; | |
| struct miscdevice miscdev; | |
| struct binder_context context; | |
| struct inode *binderfs_inode; | |
| refcount_t ref; | |
| }; | |
| /** | |
| * binderfs_mount_opts - mount options for binderfs | |
| * @max: maximum number of allocatable binderfs binder devices | |
| * @stats_mode: enable binder stats in binderfs. | |
| */ | |
| struct binderfs_mount_opts { | |
| int max; | |
| int stats_mode; | |
| }; | |
| /** | |
| * binderfs_info - information about a binderfs mount | |
| * @ipc_ns: The ipc namespace the binderfs mount belongs to. | |
| * @control_dentry: This records the dentry of this binderfs mount | |
| * binder-control device. | |
| * @root_uid: uid that needs to be used when a new binder device is | |
| * created. | |
| * @root_gid: gid that needs to be used when a new binder device is | |
| * created. | |
| * @mount_opts: The mount options in use. | |
| * @device_count: The current number of allocated binder devices. | |
| * @proc_log_dir: Pointer to the directory dentry containing process-specific | |
| * logs. | |
| */ | |
| struct binderfs_info { | |
| struct ipc_namespace *ipc_ns; | |
| struct dentry *control_dentry; | |
| kuid_t root_uid; | |
| kgid_t root_gid; | |
| struct binderfs_mount_opts mount_opts; | |
| int device_count; | |
| struct dentry *proc_log_dir; | |
| }; | |
| extern const struct file_operations binder_fops; | |
| extern char *binder_devices_param; | |
| #ifdef CONFIG_ANDROID_BINDERFS | |
| extern bool is_binderfs_device(const struct inode *inode); | |
| extern struct dentry *binderfs_create_file(struct dentry *dir, const char *name, | |
| const struct file_operations *fops, | |
| void *data); | |
| #else | |
| static inline bool is_binderfs_device(const struct inode *inode) | |
| { | |
| return false; | |
| } | |
| static inline struct dentry *binderfs_create_file(struct dentry *dir, | |
| const char *name, | |
| const struct file_operations *fops, | |
| void *data) | |
| { | |
| return NULL; | |
| } | |
| #endif | |
| #ifdef CONFIG_ANDROID_BINDERFS | |
| extern int __init init_binderfs(void); | |
| #else | |
| static inline int __init init_binderfs(void) | |
| { | |
| return 0; | |
| } | |
| #endif | |
| struct binder_debugfs_entry { | |
| const char *name; | |
| umode_t mode; | |
| const struct file_operations *fops; | |
| void *data; | |
| }; | |
| extern const struct binder_debugfs_entry binder_debugfs_entries[]; | |
| #define binder_for_each_debugfs_entry(entry) \ | |
| for ((entry) = binder_debugfs_entries; \ | |
| (entry)->name; \ | |
| (entry)++) | |
| enum binder_stat_types { | |
| BINDER_STAT_PROC, | |
| BINDER_STAT_THREAD, | |
| BINDER_STAT_NODE, | |
| BINDER_STAT_REF, | |
| BINDER_STAT_DEATH, | |
| BINDER_STAT_TRANSACTION, | |
| BINDER_STAT_TRANSACTION_COMPLETE, | |
| BINDER_STAT_FREEZE, | |
| BINDER_STAT_COUNT | |
| }; | |
| struct binder_stats { | |
| atomic_t br[_IOC_NR(BR_CLEAR_FREEZE_NOTIFICATION_DONE) + 1]; | |
| atomic_t bc[_IOC_NR(BC_FREEZE_NOTIFICATION_DONE) + 1]; | |
| atomic_t obj_created[BINDER_STAT_COUNT]; | |
| atomic_t obj_deleted[BINDER_STAT_COUNT]; | |
| }; | |
| /** | |
| * struct binder_work - work enqueued on a worklist | |
| * @entry: node enqueued on list | |
| * @type: type of work to be performed | |
| * | |
| * There are separate work lists for proc, thread, and node (async). | |
| */ | |
| struct binder_work { | |
| struct list_head entry; | |
| enum binder_work_type { | |
| BINDER_WORK_TRANSACTION = 1, | |
| BINDER_WORK_TRANSACTION_COMPLETE, | |
| BINDER_WORK_TRANSACTION_PENDING, | |
| BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT, | |
| BINDER_WORK_RETURN_ERROR, | |
| BINDER_WORK_NODE, | |
| BINDER_WORK_DEAD_BINDER, | |
| BINDER_WORK_DEAD_BINDER_AND_CLEAR, | |
| BINDER_WORK_CLEAR_DEATH_NOTIFICATION, | |
| BINDER_WORK_FROZEN_BINDER, | |
| BINDER_WORK_CLEAR_FREEZE_NOTIFICATION, | |
| } type; | |
| }; | |
| struct binder_error { | |
| struct binder_work work; | |
| uint32_t cmd; | |
| }; | |
| /** | |
| * struct binder_node - binder node bookkeeping | |
| * @debug_id: unique ID for debugging | |
| * (invariant after initialized) | |
| * @lock: lock for node fields | |
| * @work: worklist element for node work | |
| * (protected by @proc->inner_lock) | |
| * @rb_node: element for proc->nodes tree | |
| * (protected by @proc->inner_lock) | |
| * @dead_node: element for binder_dead_nodes list | |
| * (protected by binder_dead_nodes_lock) | |
| * @proc: binder_proc that owns this node | |
| * (invariant after initialized) | |
| * @refs: list of references on this node | |
| * (protected by @lock) | |
| * @internal_strong_refs: used to take strong references when | |
| * initiating a transaction | |
| * (protected by @proc->inner_lock if @proc | |
| * and by @lock) | |
| * @local_weak_refs: weak user refs from local process | |
| * (protected by @proc->inner_lock if @proc | |
| * and by @lock) | |
| * @local_strong_refs: strong user refs from local process | |
| * (protected by @proc->inner_lock if @proc | |
| * and by @lock) | |
| * @tmp_refs: temporary kernel refs | |
| * (protected by @proc->inner_lock while @proc | |
| * is valid, and by binder_dead_nodes_lock | |
| * if @proc is NULL. During inc/dec and node release | |
| * it is also protected by @lock to provide safety | |
| * as the node dies and @proc becomes NULL) | |
| * @ptr: userspace pointer for node | |
| * (invariant, no lock needed) | |
| * @cookie: userspace cookie for node | |
| * (invariant, no lock needed) | |
| * @has_strong_ref: userspace notified of strong ref | |
| * (protected by @proc->inner_lock if @proc | |
| * and by @lock) | |
| * @pending_strong_ref: userspace has acked notification of strong ref | |
| * (protected by @proc->inner_lock if @proc | |
| * and by @lock) | |
| * @has_weak_ref: userspace notified of weak ref | |
| * (protected by @proc->inner_lock if @proc | |
| * and by @lock) | |
| * @pending_weak_ref: userspace has acked notification of weak ref | |
| * (protected by @proc->inner_lock if @proc | |
| * and by @lock) | |
| * @has_async_transaction: async transaction to node in progress | |
| * (protected by @lock) | |
| * @accept_fds: file descriptor operations supported for node | |
| * (invariant after initialized) | |
| * @min_priority: minimum scheduling priority | |
| * (invariant after initialized) | |
| * @txn_security_ctx: require sender's security context | |
| * (invariant after initialized) | |
| * @async_todo: list of async work items | |
| * (protected by @proc->inner_lock) | |
| * | |
| * Bookkeeping structure for binder nodes. | |
| */ | |
| struct binder_node { | |
| int debug_id; | |
| spinlock_t lock; | |
| struct binder_work work; | |
| union { | |
| struct rb_node rb_node; | |
| struct hlist_node dead_node; | |
| }; | |
| struct binder_proc *proc; | |
| struct hlist_head refs; | |
| int internal_strong_refs; | |
| int local_weak_refs; | |
| int local_strong_refs; | |
| int tmp_refs; | |
| binder_uintptr_t ptr; | |
| binder_uintptr_t cookie; | |
| struct { | |
| /* | |
| * bitfield elements protected by | |
| * proc inner_lock | |
| */ | |
| u8 has_strong_ref:1; | |
| u8 pending_strong_ref:1; | |
| u8 has_weak_ref:1; | |
| u8 pending_weak_ref:1; | |
| }; | |
| struct { | |
| /* | |
| * invariant after initialization | |
| */ | |
| u8 accept_fds:1; | |
| u8 txn_security_ctx:1; | |
| u8 min_priority; | |
| }; | |
| bool has_async_transaction; | |
| struct list_head async_todo; | |
| }; | |
| struct binder_ref_death { | |
| /** | |
| * @work: worklist element for death notifications | |
| * (protected by inner_lock of the proc that | |
| * this ref belongs to) | |
| */ | |
| struct binder_work work; | |
| binder_uintptr_t cookie; | |
| }; | |
| struct binder_ref_freeze { | |
| struct binder_work work; | |
| binder_uintptr_t cookie; | |
| bool is_frozen:1; | |
| bool sent:1; | |
| bool resend:1; | |
| }; | |
| /** | |
| * struct binder_ref_data - binder_ref counts and id | |
| * @debug_id: unique ID for the ref | |
| * @desc: unique userspace handle for ref | |
| * @strong: strong ref count (debugging only if not locked) | |
| * @weak: weak ref count (debugging only if not locked) | |
| * | |
| * Structure to hold ref count and ref id information. Since | |
| * the actual ref can only be accessed with a lock, this structure | |
| * is used to return information about the ref to callers of | |
| * ref inc/dec functions. | |
| */ | |
| struct binder_ref_data { | |
| int debug_id; | |
| uint32_t desc; | |
| int strong; | |
| int weak; | |
| }; | |
| /** | |
| * struct binder_ref - struct to track references on nodes | |
| * @data: binder_ref_data containing id, handle, and current refcounts | |
| * @rb_node_desc: node for lookup by @data.desc in proc's rb_tree | |
| * @rb_node_node: node for lookup by @node in proc's rb_tree | |
| * @node_entry: list entry for node->refs list in target node | |
| * (protected by @node->lock) | |
| * @proc: binder_proc containing ref | |
| * @node: binder_node of target node. When cleaning up a | |
| * ref for deletion in binder_cleanup_ref, a non-NULL | |
| * @node indicates the node must be freed | |
| * @death: pointer to death notification (ref_death) if requested | |
| * (protected by @node->lock) | |
| * @freeze: pointer to freeze notification (ref_freeze) if requested | |
| * (protected by @node->lock) | |
| * | |
| * Structure to track references from procA to target node (on procB). This | |
| * structure is unsafe to access without holding @proc->outer_lock. | |
| */ | |
| struct binder_ref { | |
| /* Lookups needed: */ | |
| /* node + proc => ref (transaction) */ | |
| /* desc + proc => ref (transaction, inc/dec ref) */ | |
| /* node => refs + procs (proc exit) */ | |
| struct binder_ref_data data; | |
| struct rb_node rb_node_desc; | |
| struct rb_node rb_node_node; | |
| struct hlist_node node_entry; | |
| struct binder_proc *proc; | |
| struct binder_node *node; | |
| struct binder_ref_death *death; | |
| struct binder_ref_freeze *freeze; | |
| }; | |
| /** | |
| * struct binder_proc - binder process bookkeeping | |
| * @proc_node: element for binder_procs list | |
| * @threads: rbtree of binder_threads in this proc | |
| * (protected by @inner_lock) | |
| * @nodes: rbtree of binder nodes associated with | |
| * this proc ordered by node->ptr | |
| * (protected by @inner_lock) | |
| * @refs_by_desc: rbtree of refs ordered by ref->desc | |
| * (protected by @outer_lock) | |
| * @refs_by_node: rbtree of refs ordered by ref->node | |
| * (protected by @outer_lock) | |
| * @waiting_threads: threads currently waiting for proc work | |
| * (protected by @inner_lock) | |
| * @pid PID of group_leader of process | |
| * (invariant after initialized) | |
| * @tsk task_struct for group_leader of process | |
| * (invariant after initialized) | |
| * @cred struct cred associated with the `struct file` | |
| * in binder_open() | |
| * (invariant after initialized) | |
| * @deferred_work_node: element for binder_deferred_list | |
| * (protected by binder_deferred_lock) | |
| * @deferred_work: bitmap of deferred work to perform | |
| * (protected by binder_deferred_lock) | |
| * @outstanding_txns: number of transactions to be transmitted before | |
| * processes in freeze_wait are woken up | |
| * (protected by @inner_lock) | |
| * @is_dead: process is dead and awaiting free | |
| * when outstanding transactions are cleaned up | |
| * (protected by @inner_lock) | |
| * @is_frozen: process is frozen and unable to service | |
| * binder transactions | |
| * (protected by @inner_lock) | |
| * @sync_recv: process received sync transactions since last frozen | |
| * bit 0: received sync transaction after being frozen | |
| * bit 1: new pending sync transaction during freezing | |
| * (protected by @inner_lock) | |
| * @async_recv: process received async transactions since last frozen | |
| * (protected by @inner_lock) | |
| * @freeze_wait: waitqueue of processes waiting for all outstanding | |
| * transactions to be processed | |
| * (protected by @inner_lock) | |
| * @dmap dbitmap to manage available reference descriptors | |
| * (protected by @outer_lock) | |
| * @todo: list of work for this process | |
| * (protected by @inner_lock) | |
| * @stats: per-process binder statistics | |
| * (atomics, no lock needed) | |
| * @delivered_death: list of delivered death notification | |
| * (protected by @inner_lock) | |
| * @delivered_freeze: list of delivered freeze notification | |
| * (protected by @inner_lock) | |
| * @max_threads: cap on number of binder threads | |
| * (protected by @inner_lock) | |
| * @requested_threads: number of binder threads requested but not | |
| * yet started. In current implementation, can | |
| * only be 0 or 1. | |
| * (protected by @inner_lock) | |
| * @requested_threads_started: number binder threads started | |
| * (protected by @inner_lock) | |
| * @tmp_ref: temporary reference to indicate proc is in use | |
| * (protected by @inner_lock) | |
| * @default_priority: default scheduler priority | |
| * (invariant after initialized) | |
| * @debugfs_entry: debugfs node | |
| * @alloc: binder allocator bookkeeping | |
| * @context: binder_context for this proc | |
| * (invariant after initialized) | |
| * @inner_lock: can nest under outer_lock and/or node lock | |
| * @outer_lock: no nesting under innor or node lock | |
| * Lock order: 1) outer, 2) node, 3) inner | |
| * @binderfs_entry: process-specific binderfs log file | |
| * @oneway_spam_detection_enabled: process enabled oneway spam detection | |
| * or not | |
| * | |
| * Bookkeeping structure for binder processes | |
| */ | |
| struct binder_proc { | |
| struct hlist_node proc_node; | |
| struct rb_root threads; | |
| struct rb_root nodes; | |
| struct rb_root refs_by_desc; | |
| struct rb_root refs_by_node; | |
| struct list_head waiting_threads; | |
| int pid; | |
| struct task_struct *tsk; | |
| const struct cred *cred; | |
| struct hlist_node deferred_work_node; | |
| int deferred_work; | |
| int outstanding_txns; | |
| bool is_dead; | |
| bool is_frozen; | |
| bool sync_recv; | |
| bool async_recv; | |
| wait_queue_head_t freeze_wait; | |
| struct dbitmap dmap; | |
| struct list_head todo; | |
| struct binder_stats stats; | |
| struct list_head delivered_death; | |
| struct list_head delivered_freeze; | |
| u32 max_threads; | |
| int requested_threads; | |
| int requested_threads_started; | |
| int tmp_ref; | |
| long default_priority; | |
| struct dentry *debugfs_entry; | |
| struct binder_alloc alloc; | |
| struct binder_context *context; | |
| spinlock_t inner_lock; | |
| spinlock_t outer_lock; | |
| struct dentry *binderfs_entry; | |
| bool oneway_spam_detection_enabled; | |
| }; | |
| /** | |
| * struct binder_thread - binder thread bookkeeping | |
| * @proc: binder process for this thread | |
| * (invariant after initialization) | |
| * @rb_node: element for proc->threads rbtree | |
| * (protected by @proc->inner_lock) | |
| * @waiting_thread_node: element for @proc->waiting_threads list | |
| * (protected by @proc->inner_lock) | |
| * @pid: PID for this thread | |
| * (invariant after initialization) | |
| * @looper: bitmap of looping state | |
| * (only accessed by this thread) | |
| * @looper_needs_return: looping thread needs to exit driver | |
| * (no lock needed) | |
| * @transaction_stack: stack of in-progress transactions for this thread | |
| * (protected by @proc->inner_lock) | |
| * @todo: list of work to do for this thread | |
| * (protected by @proc->inner_lock) | |
| * @process_todo: whether work in @todo should be processed | |
| * (protected by @proc->inner_lock) | |
| * @return_error: transaction errors reported by this thread | |
| * (only accessed by this thread) | |
| * @reply_error: transaction errors reported by target thread | |
| * (protected by @proc->inner_lock) | |
| * @ee: extended error information from this thread | |
| * (protected by @proc->inner_lock) | |
| * @wait: wait queue for thread work | |
| * @stats: per-thread statistics | |
| * (atomics, no lock needed) | |
| * @tmp_ref: temporary reference to indicate thread is in use | |
| * (atomic since @proc->inner_lock cannot | |
| * always be acquired) | |
| * @is_dead: thread is dead and awaiting free | |
| * when outstanding transactions are cleaned up | |
| * (protected by @proc->inner_lock) | |
| * | |
| * Bookkeeping structure for binder threads. | |
| */ | |
| struct binder_thread { | |
| struct binder_proc *proc; | |
| struct rb_node rb_node; | |
| struct list_head waiting_thread_node; | |
| int pid; | |
| int looper; /* only modified by this thread */ | |
| bool looper_need_return; /* can be written by other thread */ | |
| struct binder_transaction *transaction_stack; | |
| struct list_head todo; | |
| bool process_todo; | |
| struct binder_error return_error; | |
| struct binder_error reply_error; | |
| struct binder_extended_error ee; | |
| wait_queue_head_t wait; | |
| struct binder_stats stats; | |
| atomic_t tmp_ref; | |
| bool is_dead; | |
| }; | |
| /** | |
| * struct binder_txn_fd_fixup - transaction fd fixup list element | |
| * @fixup_entry: list entry | |
| * @file: struct file to be associated with new fd | |
| * @offset: offset in buffer data to this fixup | |
| * @target_fd: fd to use by the target to install @file | |
| * | |
| * List element for fd fixups in a transaction. Since file | |
| * descriptors need to be allocated in the context of the | |
| * target process, we pass each fd to be processed in this | |
| * struct. | |
| */ | |
| struct binder_txn_fd_fixup { | |
| struct list_head fixup_entry; | |
| struct file *file; | |
| size_t offset; | |
| int target_fd; | |
| }; | |
| struct binder_transaction { | |
| int debug_id; | |
| struct binder_work work; | |
| struct binder_thread *from; | |
| pid_t from_pid; | |
| pid_t from_tid; | |
| struct binder_transaction *from_parent; | |
| struct binder_proc *to_proc; | |
| struct binder_thread *to_thread; | |
| struct binder_transaction *to_parent; | |
| unsigned is_async:1; | |
| unsigned is_reply:1; | |
| struct binder_buffer *buffer; | |
| unsigned int code; | |
| unsigned int flags; | |
| long priority; | |
| long saved_priority; | |
| kuid_t sender_euid; | |
| ktime_t start_time; | |
| struct list_head fd_fixups; | |
| binder_uintptr_t security_ctx; | |
| /** | |
| * @lock: protects @from, @to_proc, and @to_thread | |
| * | |
| * @from, @to_proc, and @to_thread can be set to NULL | |
| * during thread teardown | |
| */ | |
| spinlock_t lock; | |
| }; | |
| /** | |
| * struct binder_object - union of flat binder object types | |
| * @hdr: generic object header | |
| * @fbo: binder object (nodes and refs) | |
| * @fdo: file descriptor object | |
| * @bbo: binder buffer pointer | |
| * @fdao: file descriptor array | |
| * | |
| * Used for type-independent object copies | |
| */ | |
| struct binder_object { | |
| union { | |
| struct binder_object_header hdr; | |
| struct flat_binder_object fbo; | |
| struct binder_fd_object fdo; | |
| struct binder_buffer_object bbo; | |
| struct binder_fd_array_object fdao; | |
| }; | |
| }; | |
| /** | |
| * Add a binder device to binder_devices | |
| * @device: the new binder device to add to the global list | |
| */ | |
| void binder_add_device(struct binder_device *device); | |
| /** | |
| * Remove a binder device to binder_devices | |
| * @device: the binder device to remove from the global list | |
| */ | |
| void binder_remove_device(struct binder_device *device); | |
| #if IS_ENABLED(CONFIG_KUNIT) | |
| vm_fault_t binder_vm_fault(struct vm_fault *vmf); | |
| #endif | |
| #endif /* _LINUX_BINDER_INTERNAL_H */ |