在SF调用hwc的binder_f1函数中hwc调用SF的binder_f2,会导致线程的优先级从97降级为120。
sf sync binder to HWC SF优先级是97,call到HWC,HWC的优先级是97
HWC sync binder to sf 这里binder嵌套,HWC call到SF,SF的优先级被改为120了,从trace上看HWC的优先级全程是97
sf reply hwc
hwc reply sf
inder调用的优先级继承
Binder默认支持client端调用server端的时候,将Client端的线程优先级传递给server端。
在Android系统中,Binder是进程间通信(IPC)的核心机制。Binder调用涉及优先级继承(Priority Inheritance),这是一种解决优先级反转问题的机制。优先级反转是指高优先级任务因为等待低优先级任务持有的资源而被阻塞,而低优先级任务又因为中等优先级任务的抢占而无法释放资源,从而导致高优先级任务长时间无法执行。
Android的Binder机制通过优先级继承来解决这个问题:当高优先级任务等待低优先级任务持有的Binder资源时,低优先级任务会临时继承高优先级任务的优先级,从而尽快完成资源释放,避免高优先级任务被长时间阻塞。
然而,在某些情况下,可能需要降低或调整Binder调用的优先级继承行为,例如为了避免过渡提升低优先级任务的优先级,或者为了优化系统性能。
理解Binder优先级继承机制
Binder线程优先级:每个Binder线程都有一个优先级,通常由进程的优先级和线程的调度策略决定。
优先级继承:当高优先级任务等待低优先级任务持有的Binder资源时,低优先级任务会临时继承高优先级任务的优先级。
恢复优先级:当低优先级任务释放资源后,其优先级会恢复到原来的值。
降低Binder优先级继承的方法
方法1:调整Binder线程的优先级
通过修改Binder线程的优先级,可以间接影响优先级继承的行为。
使用setpriority() 或 sched_setscheduler() 系统调用调整线程的优先级。
代码示例:
#include <sys/resource.h>
#include <unistd.h>
#include <sched.h>// 设置线程的优先级
int set_thread_priority(int tid, int priority) {struct sched_param param;param.sched_priority = priority;return sched_setscheduler(tid, SCHED_FIFO, ¶m);
}
方法2:修改Binder驱动的优先级继承策略
Binder驱动的优先级继承行为可以通过修改内核代码来调整。
在Binder驱动源码中,优先级继承的逻辑通常位于binder.c文件中,具体函数为binder_transaction() 和 binder_set_priority()。
可以通过修改以下逻辑来降低优先级继承的影响:
减少优先级继承的提升幅度。
限制优先级继承的持续时间。
方法3:禁用或限制优先级继承
在某些情况下,可以完成禁用优先级继承,但是可能会导致优先级反转问题。
在Binder驱动中,可以通过修改代码来禁用优先级继承逻辑。
修改示例:
// 在 binder_transaction() 中注释掉优先级继承的逻辑
// if (target_thread->priority < current->priority) {
// binder_set_priority(target_thread, current->priority);
// }
方法4:使用Android系统属性
Android提供了一些系统属性,可以调整Binder的行为。
例如,可以通过修改debug.binder.priority属性来调整Binder线程的默认优先级。
命令示例:
adb shell setprop debug.binder.priority <value>
注意事项
优先级反转风险:降低或禁用优先级继承可能会导致优先级反转问题,从而影响系统的实时性和响应性。
系统稳定性:修改 Binder 驱动的行为可能会影响系统的稳定性,尤其是在多任务和高负载场景下。
测试和验证:在修改优先级继承逻辑后,必须进行充分的测试,确保系统性能和稳定性不受影响。
示例场景
场景 1:在实时性要求不高的系统中,降低 Binder 优先级继承以减少对低优先级任务的干扰。
场景 2:在性能测试中,禁用优先级继承以观察系统的行为。
线程优先级降级原因分析
首先查看binder驱动中的定义binder_priority接口体。
/*** struct binder_priority - scheduler policy and priority* @sched_policy scheduler policy* @prio [100..139] for SCHED_NORMAL, [0..99] for FIFO/RT** The binder driver supports inheriting the following scheduler policies:* SCHED_NORMAL* SCHED_BATCH* SCHED_FIFO* SCHED_RR*/
struct binder_priority {unsigned int sched_policy;int prio;
};
由[100..139] for SCHED_NORMAL, [0..99] for FIFO/RT
这段注释可得出,binder驱动中奖sched_prlicy
改成了SCHED_NORMAL
。
在binder驱动中搜索SCHED_NORMAL
,可以找到几处用到=SCHED_NORMAL
代码。
初始化,设置进程的default_priority
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);}
...
}
MIN_NICE是-20,对应优先级应该是100
static void binder_do_set_priority(struct binder_thread *thread,const struct binder_priority *desired,bool verify)
{
...if (verify && is_rt_policy(policy) && !has_cap_nice) {long max_rtprio = task_rlimit(task, RLIMIT_RTPRIO);if (max_rtprio == 0) {policy = SCHED_NORMAL;priority = MIN_NICE;//-20} else if (priority > max_rtprio) {priority = max_rtprio;}}
...
}
NICE_TO_PRIO(0)120
static void binder_transaction_priority(struct binder_thread *thread,struct binder_transaction *t,struct binder_node *node)
{
...if (!node->inherit_rt && is_rt_policy(desired.sched_policy)) {desired.prio = NICE_TO_PRIO(0);desired.sched_policy = SCHED_NORMAL;}
...
}
总结
当HWC
作为97
的优先级调用SF
的时候,会调用binder_transaction_priority
这个函数,由于调用SF
的binder node
的inherit_rt
为false
,并且desired.sched_policy
也就是HWC
的sched_policy
为is_rt_policy
,因为97
就是FIFO/RT
,这里具体是哪个policy
就不重要了。最后就将desired.prio
设置成了120。
static bool is_rt_policy(int policy)
{return policy == SCHED_FIFO || policy == SCHED_RR;
}
为什么SF的binder node的inherit_rt为false
因为默认aidl
的binder
对象inherit_rt
就是false
。
frameworks/native/libs/binder/Parcel.cpp
status_t Parcel::flattenBinder(const sp<IBinder>& binder) {if (binder != nullptr) {if (!local) {...} else {int policy = local->getMinSchedulerPolicy();int priority = local->getMinSchedulerPriority();if (policy != 0 || priority != 0) {// override value, since it is set explicitlyschedBits = schedPolicyMask(policy, priority);}obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;if (local->isRequestingSid()) {obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;}if (local->isInheritRt()) {//调用BBinder的isInheritRtobj.flags |= FLAT_BINDER_FLAG_INHERIT_RT;}obj.hdr.type = BINDER_TYPE_BINDER;obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());obj.cookie = reinterpret_cast<uintptr_t>(local);}} else {...}
}bool BBinder::isInheritRt() {Extras* e = mExtras.load(std::memory_order_acquire);return e && e->mInheritRt;
}
除非主动调用setInheritRT
这个接口。
void BBinder::setInheritRt(bool inheritRt) {LOG_ALWAYS_FATAL_IF(mParceled,"setInheritRt() should not be called after a binder object ""is parceled/sent to another process");Extras* e = mExtras.load(std::memory_order_acquire);if (!e) {if (!inheritRt) {return;}e = getOrCreateExtras();if (!e) return; // out of memory}e->mInheritRt = inheritRt;
}
规范的用法
BnCameraDeviceCallback
是aidl
文件自动生成的,但是要注意,需要在传递给Binder
驱动之前,对应的Binder
对象就需要设置完成。
::ndk::SpAIBinder AidlCamera3Device::AidlCameraDeviceCallbacks::createBinder() {auto binder = BnCameraDeviceCallback::createBinder();AIBinder_setInheritRt(binder.get(), /*inheritRt*/ true);//调用下面这个函数。return binder;
}void AIBinder_setInheritRt(AIBinder* binder, bool inheritRt) {ABBinder* localBinder = binder->asABBinder();if (localBinder == nullptr) {LOG(FATAL) << "AIBinder_setInheritRt must be called on a local binder";}localBinder->setInheritRt(inheritRt);
}
HWBinder的inherit_rt默认为true
HWBinder
有一些特殊,就是默认加了FLAT_BINDER_FLAG_INHERIT_RT
,所以HWBinder
默认是可以继承RT
的调度策略的。
system/libhwbinder/Parcel.cpp
status_t flatten_binder(const sp<ProcessState>& /*proc*/,const sp<IBinder>& binder, Parcel* out)
{if (binder != nullptr) {BHwBinder *local = binder->localBinder();if (!local) {} else {// Get policy and convert itint policy = local->getMinSchedulingPolicy();int priority = local->getMinSchedulingPriority();obj.flags = priority & FLAT_BINDER_FLAG_PRIORITY_MASK;obj.flags |= FLAT_BINDER_FLAG_ACCEPTS_FDS | FLAT_BINDER_FLAG_INHERIT_RT;//默认就加了obj.flags |= (policy & 3) << FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT;if (local->isRequestingSid()) {obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;}obj.hdr.type = BINDER_TYPE_BINDER;obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());obj.cookie = reinterpret_cast<uintptr_t>(local);}} else {}return finish_flatten_binder(binder, obj, out);
}
HWC
初始化Binder
服务的时候,主动调用了AIBinder_setInheritRt
。
device/generic/goldfish-opengl/system/hwc3/Composer.cpp
::ndk::SpAIBinder Composer::createBinder() {DEBUG_LOG("%s", __FUNCTION__);auto binder = BnComposer::createBinder();AIBinder_setInheritRt(binder.get(), true);return binder;
}
注意:因为HWC
改成了aidl
,也就意味着图中binder_f1
的调用和binder_f2
的响应是同一个SF
线程。