基于Linux-5.10,有补充Linux-5.15的说明
一、优先级相关结构体和成员
1. struct binder_priority
struct binder_priority { //binder_internal.h unsigned int sched_policy; int prio; };
此结构用于对服务的binder线程的调度策略和优先级进行描述。
sched_policy: 此成员表示调度策略,binder驱动只支持 SCHED_NORMAL、SCHED_BATCH、SCHED_FIFO、SCHED_RR 这几类调度策略的继承。
prio: 表示内核优先级,对于 SCHED_NORMAL 是[100..139],对于 FIFO/RT 是[0..99]。
在内核空间,此结构的prio取值[0, 139], sched_policy取内核优先级对应的策略,见 binder_proc_transaction() 中的 node_prio 变量。
2. struct binder_node
struct binder_node { //binder_internal.h ... struct { ... u8 sched_policy:2; u8 inherit_rt:1; u8 min_priority; }; };
sched_policy: 节点的binder服务线程最小优先级对应的调度策略,初始化后就不再变化了。
inherit_rt: 是否允许本服务的binder线程从caller那里继承RT调度策略。若不允许但caller又是RT线程,那么就将响应的binder线程设置为CFS 120优先级。
min_priority: 节点的binder服务线程最小调度优先级,初始化后就不再变化了。相当于将向binder线程传递的最低优先级钳位到这个值上,见 binder_transaction_priority().
是在创建binder服务时,根据用户传入的 flat_binder_object::flags 成员进行初始化,具体初始化位置在 binder_init_node_ilocked() 中:
static struct binder_node *binder_init_node_ilocked(struct binder_proc *proc, struct binder_node *new_node, struct flat_binder_object *fp) { struct binder_node *node = new_node; __u32 flags = fp ? fp->flags : 0; //优先级相关配置来自flags成员 s8 priority; ... priority = flags & FLAT_BINDER_FLAG_PRIORITY_MASK; node->sched_policy = (flags & FLAT_BINDER_FLAG_SCHED_POLICY_MASK) >> FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT; /*用户配置下来的是用户优先级,需要转换 */ node->min_priority = to_kernel_prio(node->sched_policy, priority); node->inherit_rt = !!(flags & FLAT_BINDER_FLAG_INHERIT_RT); ... }
调用路径:
binder_thread_write //1.注册binder服务时 binder_transaction binder_translate_binder binder_translate_binder binder_ioctl_set_ctx_mgr //2.将自己设置为servicemanage时 binder_new_node binder_init_node_ilocked
假设服务还没注册,就还不存在于 proc->nodes 红黑树上,此时就是对参数 new_node 进行初始化。可以看到优先级和调度策略都是来自 flat_binder_object::flags 成员,根据用户传下来的调度策略和优先级转化成一个内核优先级,保存在 node->min_priority 成员中。
开机启动过程中:
(1) 对于 min_priority 成员,主要是主线程是 system_server 的线程(超大量)创建 binder_node 时传参 min_priority=120,其它如主线程是 com.android.phone、MmsServiceMain、idmap2d、com.qti.ltebc 等也有传
min_priority=120 的情况,其它绝大多数线程传的 min_priority=139。而且只有120和139这两个配置值。
(2) 对于 sched_policy 成员,全部传的都是0(SCHED_NORMAL)。
(3) 对于 inherit_rt 成员,极个别的传的是1,比如主线程是 perf-hal-servic、m.android.phone 等的线程,其它的都是0。
在正常使用手机的过程中,也会不停的创建binder node。
3. struct binder_proc
struct binder_proc { //binder_internal.h ... struct binder_priority default_priority; };
default_priority: 在调用 binder_open() 时进行赋值,若调用者是CFS或RT线程,直接赋值为调用者的优先级,若是不支持的调度策略则赋值为prio=120的CFS优先级。
static int binder_open(struct inode *nodp, struct file *filp) { ... if (binder_supported_policy(current->policy)) { proc->default_priority.sched_policy = current->policy; proc->default_priority.prio = current->normal_prio; } else { proc->default_priority.sched_policy = SCHED_NORMAL; proc->default_priority.prio = NICE_TO_PRIO(0); } ... }
开机启动过程中,一般都是主线程执行 binder_open() 的动作,但是也有个别特殊情况,比如辅线程 PowerManagerSer(主线程system_server)、surfaceflinger 也执行了打开binder设备节点的操作。
开机启动过程中:
(1) 对于 default_priority.sched_policy 全部赋值为0(SCHED_NORMAL)
(2) 对于 default_priority.prio 绝大多数都是120,只有极个别是116,104,97等。
在正常使用机器的过程中,也会有不断打开binder节点的动作。
4. struct binder_transaction
struct binder_transaction { ... struct binder_priority priority; struct binder_priority saved_priority; bool set_priority_called; ... }
priority: 对于同步传输赋值为发起传输的caller的优先级(虽然没有区分reply,但是reply没有使用这个成员)。对异步传输赋值为目标进程的 target_proc->default_priority。若binder不支持
caller的调度策略,也赋值为target_proc->default_priority,见 binder_transaction()。
saved_priority: 在将要改变server的binder线程的优先级时,将其保存在这个成员中,以便之后进行恢复。见发起传输时的 binder_transaction_priority() 和 binder_transaction() 的reply部分。
set_priority_called: 在 binder_transaction_priority() 中唯一判断和设置。在client端发起传输和service的binder线程读取传输时都有设置binder优先级动作,这个成员标记针对当前 transaction t 的优先级传递是否已经设置了。若选到了thread,则在发起传输的caller进行传输进行时进行设置,若是没有选到thread,则在binder线程读取时进行设置。
//发起设置: binder_proc_transaction struct binder_priority node_prio; node_prio.prio = node->min_priority; node_prio.sched_policy = node->sched_policy; /* 若是选到了thread,挂在thread->todo链表上是才会设置,挂在proc->todo和node->async_todo上时都不会设置 */ if (thread) { binder_transaction_priority(thread->task, t, node_prio, node->inherit_rt); binder_enqueue_thread_work_ilocked(thread, &t->work); } //读取设置: binder_thread_read /* 此判断表示是服务端读取 */ if (t->buffer->target_node) { struct binder_priority node_prio; node_prio.sched_policy = target_node->sched_policy; node_prio.prio = target_node->min_priority; binder_transaction_priority(current, t, node_prio, target_node->inherit_rt); }
5. binder_pri_desc/binder_pri_ptr_cookie
struct binder_pri_desc { //uapi/binder.h __s32 priority; __u32 desc; }; struct binder_pri_ptr_cookie { //uapi/binder.h __s32 priority; binder_uintptr_t ptr; binder_uintptr_t cookie; };
对应 binder 优先级相关 ioctl 设置的参数,目前还不支持设置。
6. flat_binder_object::flags
enum flat_binder_object_shifts { FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT = 9, }; enum flat_binder_object_flags { ... FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff, FLAT_BINDER_FLAG_SCHED_POLICY_MASK = 3U << FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT, FLAT_BINDER_FLAG_INHERIT_RT = 0x800, ... };
此结构用来定义户空间设置下来的 flat_binder_object::flags 成员各个bit位的含义,在注册服务创建 binder_node 时在 binder_init_node_ilocked() 函数中进行解析。
FLAT_BINDER_FLAG_PRIORITY_MASK:最小调度优先级的位掩码。这些位可用于设置进入该node的事务应运行的最低调度优先级。这些位中的有效值取决于@FLAT_BINDER_FLAG_SCHED_POLICY_MASK 中编码的调度策略。
SCHED_NORMAL/SCHED_BATCH,有效范围在 [-20..19] 之间,对于 SCHED_FIFO/SCHED_RR,该值可以在 [1..99] 之间运行。
FLAT_BINDER_FLAG_SCHED_POLICY_MASK: 调度策略的位掩码。这两位可用于设置该Node上的事务应运行的最小调度策略。这些匹配 UAPI 调度程序策略值,例如:0=SCHED_NORMAL, 1=SCHED_FIFO, 2=SCHED_RR, 3=SCHED_BATCH.
FLAT_BINDER_FLAG_INHERIT_RT: 节点是否继承RT策略。仅当设置时,对该Node的调用将继承调用者的实时调度策略(用于同步传输)。
二、优先级相关函数
1. 底层函数
static bool is_rt_policy(int policy) { return policy == SCHED_FIFO || policy == SCHED_RR; } static bool is_fair_policy(int policy) { return policy == SCHED_NORMAL || policy == SCHED_BATCH; } /* binder只支持RT和CFS */ static bool binder_supported_policy(int policy) { return is_fair_policy(policy) || is_rt_policy(policy); } /* 内核优先级转用户优先级 */ static int to_userspace_prio(int policy, int kernel_priority) { if (is_fair_policy(policy)) return PRIO_TO_NICE(kernel_priority); else return MAX_USER_RT_PRIO - 1 - kernel_priority; } /* 用户优先级转内核优先级 */ static int to_kernel_prio(int policy, int user_priority) { if (is_fair_policy(policy)) return NICE_TO_PRIO(user_priority); else return MAX_USER_RT_PRIO - 1 - user_priority; } /* 被 binder_transaction_priority 唯一调用 */ static void binder_set_priority(struct task_struct *task, struct binder_priority desired) { /* set的时候是需要verify的 */ binder_do_set_priority(task, desired, /* verify = */ true); } static void binder_restore_priority(struct task_struct *task, struct binder_priority desired) { /* restore的时候不需要verify的 */ binder_do_set_priority(task, desired, /* verify = */ false); }
2. binder_transaction_priority() 函数实现
static void binder_transaction_priority(struct task_struct *task, struct binder_transaction *t, struct binder_priority node_prio, bool inherit_rt) { struct binder_priority desired_prio = t->priority; bool skip = false; /* 对此成员唯一判断和赋值路径 */ if (t->set_priority_called) return; /* 保存到 saved_priority 成员中 */ t->set_priority_called = true; t->saved_priority.sched_policy = task->policy; t->saved_priority.prio = task->normal_prio; trace_android_vh_binder_priority_skip(task, &skip); if (skip) return; /* 若目标是RT线程,但是又不允许继承RT,就改为prio=120的CFS优先级 */ if (!inherit_rt && is_rt_policy(desired_prio.sched_policy)) { desired_prio.prio = NICE_TO_PRIO(0); desired_prio.sched_policy = SCHED_NORMAL; } /* binder最低优先级限制还比发起传输的线程优先级高,那就取优先级高的 */ if (node_prio.prio < t->priority.prio || (node_prio.prio == t->priority.prio && node_prio.sched_policy == SCHED_FIFO)) { /* * 翻译:如果Node上的最低优先级较高(数值较小),请使用Node的优先级。 * 如果优先级相同,但Node服务的使用的是 SCHED_FIFO(大部分设置的就是它),则首选 * SCHED_FIFO,因为与 SCHED_RR 不同,它可以无限运行。 */ desired_prio = node_prio; } /* 实际设置优先级的函数 */ binder_set_priority(task, desired_prio); trace_android_vh_binder_set_priority(t, task); }
binder_set_priority() 只是调用 binder_do_set_priority(task, desired, /* verify = */ true),后者实现如下:
/* * 若传参 verify=true,会校验task是否有 CAP_SYS_NICE 权限,若没有,只能设置到其 * rlimt运行的最高优先级。若传false则没有这个校验。 */ static void binder_do_set_priority(struct task_struct *task, struct binder_priority desired, bool verify) { int priority; /* user-space prio value */ bool has_cap_nice; unsigned int policy = desired.sched_policy; /* task的优先级已经和要设置的优先级是一样的了,直接退出 */ if (task->policy == policy && task->normal_prio == desired.prio) return; has_cap_nice = has_capability_noaudit(task, CAP_SYS_NICE); /* 这里又转换为用户优先级 */ priority = to_userspace_prio(policy, desired.prio); /* 需要校验,要设为RT,又没有 CAP_SYS_NICE 权限(若有这个权限就可以忽略rlimit限制) */ if (verify && is_rt_policy(policy) && !has_cap_nice) { /* * 为0表示task不允许被设置为RT线程,那就设置为prio=100 * 的CFS线程,否则设置为最大允许的RT优先级。 * 注: 上面已经转换为用户Rt优先级了,数值越大优先级越高。 */ long max_rtprio = task_rlimit(task, RLIMIT_RTPRIO); if (max_rtprio == 0) { policy = SCHED_NORMAL; priority = MIN_NICE; } else if (priority > max_rtprio) { priority = max_rtprio; } } /* 需要校验,要设为CFS,又没有 CAP_SYS_NICE 权限 */ if (verify && is_fair_policy(policy) && !has_cap_nice) { /* 只能设置到task所支持的最大CFS优先级 */ long min_nice = rlimit_to_nice(task_rlimit(task, RLIMIT_NICE)); if (min_nice > MAX_NICE) { binder_user_error("%d RLIMIT_NICE not set\n", task->pid); return; } else if (priority < min_nice) { priority = min_nice; } } /* 实际设置的和外部传参要求设置的不一致,给个debug打印 */ if (policy != desired.sched_policy || to_kernel_prio(policy, priority) != desired.prio) binder_debug(BINDER_DEBUG_PRIORITY_CAP, "%d: priority %d not allowed, using %d instead\n", task->pid, desired.prio, to_kernel_prio(policy, priority)); /* * 这个会打印出task设置前的优先级,要设置的优先级和调用者希望设置的优先级 * HwBinder:2957_2-4054 [001] ...2 101180.500974: binder_set_priority: proc=1490 thread=1490 old=120 => new=105 desired=105 //binder线程优先级升高 * Loc_hal_worker-1426 [000] ...2 101334.089782: binder_set_priority: proc=2957 thread=7091 old=105 => new=120 desired=120 //binder线程优先级降低 */ trace_binder_set_priority(task->tgid, task->pid, task->normal_prio, to_kernel_prio(policy, priority), desired.prio); /* Set the actual priority */ /* * 设置调度策略和RT优先级,对于正在运行的任务,从trace上看这个设置不会打断其运行。 * 若是RT设置为CFS,这个函数调用后设置为CFS 120优先级。 * * 对于policy=0,prio=0的设置,下面因判断不是fair policy,就只设置成了CFS 120优先级。 */ if (task->policy != policy || is_rt_policy(policy)) { struct sched_param params; params.sched_priority = is_rt_policy(policy) ? priority : 0; sched_setscheduler_nocheck(task, policy | SCHED_RESET_ON_FORK, ¶ms); } /* 设置CFS优先级 */ if (is_fair_policy(policy)) set_user_nice(task, priority); }
binder_transaction_priority()函数作用: 将task设置为 t->priority 指定的优先级。但是受参数和服务对自己binder优先级配置的影响,设置逻辑如下:
(1) 若服务配置不允许自己的binder线程继承RT优先级,而 t->priority 又是RT线程,就将响应的binder线程设置为优先级为120的CFS线程。
(2) 若服务允许自己binder线程运行的最低优先级比 t->priority 还高,就将响应的binder线程设置为服务允许的最低优先级。
(3) 底层函数传参 verify=true,还会校验 CAP_SYS_NICE 权限,若没有这个权限,只能设置 rlimit 允许的最高优先级。
3. 从函数调用路径中可以看出,这组优先级传递函数中,对外的函数分别是 binder_transaction_priority() 和 binder_restore_priority(),则看这两个函数的调用路径:
(1) binder_transaction_priority 调用路径
binder_ioctl case BINDER_WRITE_READ: binder_ioctl_write_read binder_thread_write case BC_TRANSACTION/BC_REPLY: binder_transaction(proc, thread, &tr, cmd == BC_REPLY, 0); //好像没用这里 case BC_TRANSACTION_SG/BC_REPLY_SG: //4.X内核上用这个 binder_transaction(proc, thread, &tr.transaction_data, cmd == BC_REPLY_SG, tr.buffers_size); binder_proc_transaction //发起同步传输 binder_transaction_priority //《调用路径1》 binder_proc_transaction //发起的异步传输 binder_transaction_priority //《调用路径2》 binder_ioctl case BINDER_WRITE_READ: binder_ioctl_write_read(filp, cmd, arg, thread); binder_thread_read binder_transaction_priority //同步传输服务端读 《调用路径3》
(2) binder_restore_priority 调用路径:
binder_ioctl case BINDER_WRITE_READ: binder_ioctl_write_read(filp, cmd, arg, thread); binder_thread_read if (wait_for_proc_work) binder_restore_priority(current, proc->default_priority); //将要休眠《调用路径4》 binder_ioctl case BINDER_WRITE_READ: binder_ioctl_write_read binder_thread_write case BC_TRANSACTION_SG/BC_REPLY_SG: binder_transaction if (reply) binder_restore_priority(current, in_reply_to->saved_priority); //对同步传输的reply《调用路径5》 if (in_reply_to) binder_restore_priority(current, in_reply_to->saved_priority); //这个是传输报错后的处理路径
可见,binder优先级的传递都发生在 ioctl write/read 时刻。要搞清楚优先级传递,只需要搞清 binder_transaction_priority() 和 binder_restore_priority() 在各种传输场景下各参数和 t->priority 含义即可。
三、优先级传递逻辑
1. client sync transaction
static void binder_transaction(struct binder_proc *proc, struct binder_thread *thread, struct binder_transaction_data *tr, int reply, binder_size_t extra_buffers_size) { struct binder_transaction *t, *in_reply_to = NULL;; if (reply) { /* client端发起请求时创建的binder_transaction结构 */ in_reply_to = thread->transaction_stack; } ... /* 同步传输(但是也没区分reply,单reply不用此成员),赋值的是调用线程的优先级 */ if (!(t->flags & TF_ONE_WAY) && binder_supported_policy(current->policy)) { /* Inherit supported policies for synchronous transactions */ t->priority.sched_policy = current->policy; t->priority.prio = current->normal_prio; } else { /* Otherwise, fall back to the default priority 赋值为目标主线程优先级 */ t->priority = target_proc->default_priority; } t->work.type = BINDER_WORK_TRANSACTION; if (reply) { //reply /* 对同步传输的reply, 将服务的binder线程设置为之前的优先级 */ binder_restore_priority(current, in_reply_to->saved_priority); //《调用路径5》 } else if (!(t->flags & TF_ONE_WAY)) { //sync transaction t->need_reply = 1; t->from_parent = thread->transaction_stack; thread->transaction_stack = t; binder_inner_proc_unlock(proc); /* 此函数中会传递优先级 */ binder_proc_transaction(t, target_proc, target_thread); } else { //async transaction binder_proc_transaction(t, target_proc, NULL); } ... } static int binder_proc_transaction(struct binder_transaction *t, struct binder_proc *proc, struct binder_thread *thread) { thread = binder_select_thread_ilocked(proc); if (thread) { /* 不区分同步传输还是异步传输 */ binder_transaction_priority(thread->task, t, node_prio, node->inherit_rt); //《调用路径1》《调用路径2》 /* 将work放在binder线程的thread->todo链表上 */ binder_enqueue_thread_work_ilocked(thread, &t->work); } else if (!pending_async) { /* 若是挂在其它链表上则不会设置优先级 */ binder_enqueue_work_ilocked(&t->work, &proc->todo); } else { binder_enqueue_work_ilocked(&t->work, &node->async_todo); } ... if (!pending_async) /* 然后唤醒服务的binder线程 */ binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */); ... }
此过程对应上面《调用路径1》,binder_proc_transaction 调用传参 (thread->task, t, node_prio, node->inherit_rt),参数依次为:
thread->task:响应请求的服务的binder线程,
t: 发起传输的 client 构造的,其 t->priority 成员同步传输来自调用线程,异步传输来自 target_proc->default_priority,见 binder_transaction()。
node_prio: 服务 node 对自己的 binder 线程指定的最小优先级限制,分别取自 node->min_priority/node->sched_policy。
node->inherit_rt: 服务是否允许自己的 binder 线程继承RT优先级, 创建服务时由用户的 flat_binder_object::flags 配置,若不允许,当RT线程call过来时就将服务的binder线程设置为prio=120的CFS优先级。
解释起来就是在client发起同步传输过程中尝试将响应我们请求的 binder 线程设置为发起binder传输的线程的优先级。但是设置下去的最终优先级是受 binder_node 对地板和 CAP_SYS_NICE 对天花板的限制的。
2. client async transaction
此过程对应上面《调用路径2》,和上面同步传输过程几乎一致,不同点在于对于异步传输中 t->priority 来自 target_proc->default_priority,也就是服务端执行 binder_open() 线程的优先级。
解释起来就是在client发起异步传输过程中尝试将响应我们请求的 binder 线程设置为服务端执行 binder_open() 线程的优先级(一般是服务主线程)。
3. server read sync transaction
static int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, binder_size_t *consumed, int non_block) { int wait_for_proc_work; /* * 判断一个thread能否用来处理proc的work,对于同步传输,thread->transaction_stack 不为NULL, * 对于同步传输和异步传输 thread->todo 链表上都有work, 就返回false。 * 只有对于异步的又没有选到thread线程将work挂在proc->todo链表上时的请求才可能返回true,但是 * 概率应该较低,虽然这里设置成了proc->default_priority(异步传输t->priority保存的也是service * 执行binder_open()时的优先级),下面会再次根据t来进行设置的,不会出现优先级出错。 * * 但是线程在处理完同步/异步请求之后,要进行阻塞休眠时的下一次读,这里会返回true,因此要 * 进入休眠的binder线程会设置为 proc->default_priority。 */ wait_for_proc_work = binder_available_for_proc_work_ilocked(thread); if (wait_for_proc_work) { /* 应该是 */ binder_restore_priority(current, proc->default_priority); //《调用路径4》 } /* 平时无work要处理时在这里休眠 */ binder_wait_for_work(thread, wait_for_proc_work); while (1) { struct binder_work *w = NULL; struct binder_transaction *t = NULL; /* 能处理proc的work才会从proc->todo链表上取任务下来 */ if (!binder_worklist_empty_ilocked(&thread->todo)) list = &thread->todo; else if (!binder_worklist_empty_ilocked(&proc->todo) && wait_for_proc_work) list = &proc->todo; switch (w->type) { case BINDER_WORK_TRANSACTION: { binder_inner_proc_unlock(proc); t = container_of(w, struct binder_transaction, work); } break; ... } ... /* server端读取执行位置 */ if (t->buffer->target_node) { /* 目标服务node, 对于service的binder线程就是自己服务的node */ struct binder_node *target_node = t->buffer->target_node; struct binder_priority node_prio; trd->target.ptr = target_node->ptr; trd->cookie = target_node->cookie; node_prio.sched_policy = target_node->sched_policy; node_prio.prio = target_node->min_priority; /* 对于work对于的每一个transaction都执行,此时current就是服务的binder线程 */ binder_transaction_priority(current, t, node_prio, target_node->inherit_rt); //《调用路径3》 cmd = BR_TRANSACTION; } else { /* client端读取执行位置 */ trd->target.ptr = 0; trd->cookie = 0; cmd = BR_REPLY; } } ... }
对应于《调用路径3》,service端读取时,对于每一个work对应的transaction都会执行 binder_transaction_priority(), 由于通过 t->set_priority_called 做了针对一个t防止重复设置的机制,
若是从thread->todo链表上取下来的work不会执行,若是从proc->todo链表上取下来的才会执行。
4. server read async transaction
也对应于《调用路径3》,对于异步传输,虽然《调用路径4》也有可能对binder线程进行设置,但是随后又会在下面《调用路径3》中设置回t->priority。
对于《调用路径4》的传参可以看出,service执行open(/dev/binder)节点后再设置其优先级是不合适的,因为其 proc->default_priority 成员只在open binder节点时赋值一次,但是surfaceflinger偏偏在
open节点之后设置了自己的优先级。
4. server reply
对应于《调用路径5》, service端在对client端进行reply时会将自己binder线程的优先级设置回之前的状态。
5. client read
client读取路径中不涉及优先级传递。
四、优先级相关Trace和HOOK
1. 相关DEBUG Trace
(1) 打印binder线程当前的优先级和期望设置的优先级和最终要被设置的优先级
binder_do_set_priority trace_binder_set_priority(task->tgid, task->pid, task->normal_prio, to_kernel_prio(policy, priority), desired.prio); HwBinder:1643_2-2089 [003] ..... 6910.598526: binder_set_priority: proc=1643 thread=2089 old=120 => new=97 desired=97 HwBinder:1643_2-2089 [003] ..... 6910.615109: binder_set_priority: proc=1643 thread=2089 old=97 => new=0 desired=0
2. 相关DEBUG Log
(1) 实际设置值和外部传参不同时给个打印
binder_do_set_priority binder_debug(BINDER_DEBUG_PRIORITY_CAP, "%d: priority %d not allowed, using %d instead\n", task->pid, desired.prio, to_kernel_prio(policy, priority)); # echo 8192 > /sys/module/binder/parameters/debug_mask //使对此mask(1<<13)的打印生效
补充:
Linux-5.15内核中改动:
binder_do_set_priority binder_debug(BINDER_DEBUG_PRIORITY_CAP, "%d: priority %d not allowed, using %d instead\n", task->pid, desired->prio, to_kernel_prio(policy, priority)); binder_debug(BINDER_DEBUG_PRIORITY_CAP, "%d: %s: aborting priority restore\n", thread->pid, __func__); binder_transaction_priority binder_debug(BINDER_DEBUG_PRIORITY_CAP, "%d: saved pending priority %d\n", current->pid, thread->prio_next.prio); # dmesg -c | grep binder [ 6448.719215] binder: 17920: saved pending priority 120 [ 6764.256906] binder: 1792: priority 98 not allowed, using 100 instead ...
3. 相关HOOK
binder_transaction_priority trace_android_vh_binder_priority_skip(task, &skip); //用户可以决定是否传递优先级 trace_android_vh_binder_set_priority(t, task); //传递完后也给个HOOK binder_transaction trace_android_vh_binder_restore_priority(in_reply_to, current); //只在reply时有一个 trace_android_vh_binder_restore_priority(in_reply_to, current); //传输失败时 binder_thread_read trace_android_vh_binder_restore_priority(NULL, current); //处理proc的work路径中
五、总结
1. 用户空间对服务node优先级的配置是通过 flat_binder_object::flags 成员设置下来的,见 binder_init_node_ilocked()。
2. binder优先级传递其实就只是对service的binder线程进行的设置。简要总结起来就是在client发起同步binder请求时,尝试将响应请求的binder线程设置为发起线程的优先级,但是对优先级有个限制,不能低于binder node指定的最低优先级,也不能高于rlimit限制的优先级(若无 CAP_SYS_NICE 权限),在reply时对binder线程的优先级进行恢复; 当client发送异步请求时会进行同样的尝试,将响应请求的binder线程设置为service主线打开binder节点时的优先级(proc->default_priority)后进行响应。
3. 当binder线程没有事情做要休眠等待work时,也会设置为 proc->default_priority, 然后休眠等待.
4. 启动服务时在rc脚本中使用"capabilities SYS_NICE"给服务赋予 CAP_SYS_NICE 权限。
5. 优先级的设置是 per-binder_transaction t 的,对于每一个t都会进行一次优先级传递。
标签:node,优先级,prio,Binder,priority,binder,policy From: https://www.cnblogs.com/hellokitty2/p/16852917.html