前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[095]Binder调用的优先级降级

[095]Binder调用的优先级降级

作者头像
王小二
发布2024-04-20 11:11:03
1310
发布2024-04-20 11:11:03
举报

背景

这是一个来自朋友的疑问,在sf调用hwcbinder_f1的函数中hwc调用sfbinder_f2,会导致线程的优先级从97降级为120

代码语言:javascript
复制
请教一下,binder嵌套调用的优先级是怎么设定的呀
现在嵌套流程是这样的
1, sf sync binder to HWC    SF优先级是97,call到HWC,HWC的优先级是97
2, HWC sync binder to sf     这里binder嵌套,HWC call到SF,SF的优先级被改为120了,从trace上看HWC的优先级全程是97,不知道这个120是哪来的
3, sf reply hwc
4, hwc reply sf;

一、基础知识-Binder调用的优先级继承

我们要知道,Binder默认支持client端调用server端的时候,将client端的线程优先级传递给server端。

用的知识点可以参考我这篇《[051]Binder线程优先级继承

二、为什么线程优先级反而降了呢?

按照上面的知识点,从表面来看,不应该降级啊,我也很好奇为什么,接下来我来讲讲我的分析历程。

首先我拿到的信息就是120,我查看了binder驱动中的定义binder_priority接口体。

代码语言:javascript
复制
/**
 * 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_policy改成了SCHED_NORMAL

继续在binder驱动中搜SCHED_NORMAL,只有三处 = SCHED_NORMAL代码,我们来一一排除分析一下。

第一处:这是初始化,设置的进程的default_priority,应该不是这里降级的。
代码语言:javascript
复制
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,所以也不是这里改的
代码语言:javascript
复制
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,应用就是这里改的。
代码语言:javascript
复制
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这个函数,由于调用sfbinder nodeinherit_rtfalse,并且desired.sched_policy也就是HWCsched_policyis_rt_policy,因为97就是FIFO/RT,这里具体是哪个policy就不重要了。最后就将desired.prio设置成了120

代码语言:javascript
复制
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

代码语言:javascript
复制
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()) {//调用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;
}

除非你主动调用setInheritRt这个接口

代码语言:javascript
复制
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对象就需要设置完成。

代码语言:javascript
复制
::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);
}
小结

至此如何解决问题,只要找到HWC调用SF的接口对应的Binder对象,在初始化的地方,按照上述规范用法就可以了。

四、HWBinder的inherit_rt默认为true

HwBinder有一些特殊,就是默认加了FLAT_BINDER_FLAG_INHERIT_RT,所以HwBinder默认是可以继承RT的调度策略的。

代码语言:javascript
复制
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;//默认就加了
            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已经改成aidl,朋友的设备恰好是Android U,那问题的开头SF调用HWC的binder的时候为什么没有降级呢。聪明的你应该想到了,就是在HWC初始化Binder服务的时候,主动调用了AIBinder_setInheritRt,具体HWC代码要看供应商,这个是AOSP中代码例子。

代码语言:javascript
复制
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线程。

这个知识点可以参考我之前的文章《[031]Binder线程栈复用

总结

每次自己感觉对binder已经很了解,总会有新的问题触及自己的知识盲区,binder真的博大精深。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-04-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 一、基础知识-Binder调用的优先级继承
  • 二、为什么线程优先级反而降了呢?
  • 三、为什么sf的binder node的inherit_rt为false
    • 规范的用法
    • 四、HWBinder的inherit_rt默认为true
    • 总结
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档