背景
這是一個(gè)來自朋友的疑問,在sf調(diào)用hwc的binder_f1的函數(shù)中hwc調(diào)用sf的binder_f2,會(huì)導(dǎo)致線程的優(yōu)先級(jí)從97降級(jí)為120。
請(qǐng)教一下,binder嵌套調(diào)用的優(yōu)先級(jí)是怎么設(shè)定的呀
現(xiàn)在嵌套流程是這樣的
1, sf sync binder to HWC SF優(yōu)先級(jí)是97,call到HWC,HWC的優(yōu)先級(jí)是97
2, HWC sync binder to sf 這里binder嵌套,HWC call到SF,SF的優(yōu)先級(jí)被改為120了,從trace上看HWC的優(yōu)先級(jí)全程是97,不知道這個(gè)120是哪來的
3, sf reply hwc
4, hwc reply sf;

一、基礎(chǔ)知識(shí)-Binder調(diào)用的優(yōu)先級(jí)繼承
我們要知道,Binder默認(rèn)支持client端調(diào)用server端的時(shí)候,將client端的線程優(yōu)先級(jí)傳遞給server端。
用的知識(shí)點(diǎn)可以參考我這篇《[051]Binder線程優(yōu)先級(jí)繼承》
二、為什么線程優(yōu)先級(jí)反而降了呢?
按照上面的知識(shí)點(diǎn),從表面來看,不應(yīng)該降級(jí)啊,我也很好奇為什么,接下來我來講講我的分析歷程。
首先我拿到的信息就是120,我查看了binder驅(qū)動(dòng)中的定義binder_priority接口體。
/**
* struct binder_priority - scheduler policy and priority
* @sched_policy scheduler policy
* @prio [100..139] for SCHED_NORMAL, [0..99] for FIFO/RT //這個(gè)線索很關(guān)鍵
*
* 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;
};
根據(jù)[100..139] for SCHED_NORMAL, [0..99] for FIFO/RT這個(gè)注釋,可以知道肯定在binder驅(qū)動(dòng)中將sched_policy改成了SCHED_NORMAL
繼續(xù)在binder驅(qū)動(dòng)中搜SCHED_NORMAL,只有三處 = SCHED_NORMAL代碼,我們來一一排除分析一下。
第一處:這是初始化,設(shè)置的進(jìn)程的default_priority,應(yīng)該不是這里降級(jí)的。
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,對(duì)應(yīng)優(yōu)先級(jí)應(yīng)該是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,應(yīng)用就是這里改的。
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;
}
...
現(xiàn)場(chǎng)還原
當(dāng)HWC作為97的優(yōu)先級(jí)調(diào)用SF的時(shí)候,會(huì)調(diào)用binder_transaction_priority這個(gè)函數(shù),由于調(diào)用sf的binder node的inherit_rt為false,并且desired.sched_policy也就是HWC的sched_policy為is_rt_policy,因?yàn)?code>97就是FIFO/RT,這里具體是哪個(gè)policy就不重要了。最后就將desired.prio設(shè)置成了120。
static bool is_rt_policy(int policy)
{
return policy == SCHED_FIFO || policy == SCHED_RR;
}
三、為什么sf的binder node的inherit_rt為false
因?yàn)槟J(rèn)aidl的binder對(duì)象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 explicitly
schedBits = schedPolicyMask(policy, priority);
}
obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
if (local->isRequestingSid()) {
obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
}
if (local->isInheritRt()) {//調(diào)用BBinder的isInheritRt
obj.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;
}
除非你主動(dòng)調(diào)用setInheritRt這個(gè)接口
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;
}
規(guī)范的用法
更加規(guī)范的用法是這樣子設(shè)置,BnCameraDeviceCallback是aidl文件自動(dòng)生成的,但是要注意,需要在傳遞給Binder驅(qū)動(dòng)之前,對(duì)應(yīng)的Binder對(duì)象就需要設(shè)置完成。
::ndk::SpAIBinder AidlCamera3Device::AidlCameraDeviceCallbacks::createBinder() {
auto binder = BnCameraDeviceCallback::createBinder();
AIBinder_setInheritRt(binder.get(), /*inheritRt*/ true);//調(diào)用下面這個(gè)函數(shù)。
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);
}
小結(jié)
至此如何解決問題,只要找到HWC調(diào)用SF的接口對(duì)應(yīng)的Binder對(duì)象,在初始化的地方,按照上述規(guī)范用法就可以了。
四、HWBinder的inherit_rt默認(rèn)為true
HwBinder有一些特殊,就是默認(rèn)加了FLAT_BINDER_FLAG_INHERIT_RT,所以HwBinder默認(rèn)是可以繼承RT的調(diào)度策略的。
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 it
int 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;//默認(rèn)就加了
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);
}
但是有意思的Android U上HWC已經(jīng)改成aidl,朋友的設(shè)備恰好是Android U,那問題的開頭SF調(diào)用HWC的binder的時(shí)候?yàn)槭裁礇]有降級(jí)呢。聰明的你應(yīng)該想到了,就是在HWC初始化Binder服務(wù)的時(shí)候,主動(dòng)調(diào)用了AIBinder_setInheritRt,具體HWC代碼要看供應(yīng)商,這個(gè)是AOSP中代碼例子。
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;
}
這里還有一個(gè)細(xì)節(jié)大家要知道,因?yàn)镠WC改成了aidl,也就意味著圖中binder_f1的調(diào)用和binder_f2的響應(yīng)是同一個(gè)sf線程。
這個(gè)知識(shí)點(diǎn)可以參考我之前的文章《[031]Binder線程棧復(fù)用》

總結(jié)
每次自己感覺對(duì)binder已經(jīng)很了解,總會(huì)有新的問題觸及自己的知識(shí)盲區(qū),binder真的博大精深。