[095]Binder調(diào)用的優(yōu)先級(jí)降級(jí)

背景

這是一個(gè)來自朋友的疑問,在sf調(diào)用hwcbinder_f1的函數(shù)中hwc調(diào)用sfbinder_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)用sfbinder nodeinherit_rtfalse,并且desired.sched_policy也就是HWCsched_policyis_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真的博大精深。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容