Android4.4深入浅出之SurfaceFlinger与Client通信框架(一)

2023-11-11


               SurfaceFlinger框架是基于Binder进程间通信机制搭建的,SF作为一个服务进程,用户程序想要跟它通信必然要经过Binder机制。首先说一下,用户要跟SF通信,那么SF必须出现在ServiceManager中,因为SF也是一个服务,所有的服务都由ServiceManager来进行统一管理。在系统启动的过程中,SF就在ServiceManager中注册好了,注册好之后,SF在后台中监视一些surface的变化从而做出处理。

             而启动之后,用户程序想操作一些跟surface有关的动作,就必须和SF进行交互。而这种交互是基于Binder进程间通信机制的。下面是一张图简单说明了SF的基本框架:

大体结构是这样,有些地方有些小错误用图形不能很好的表达。用文字来说明一下:
当应用程序需要请求SurfaceFlinger服务时,首先需要构造SurfaceComposerClient对象,通过SurfaceComposerClient对象就可以访问SurfaceFlinger服务了。基本的服务流程都是这么走的,我们看一下SurfaceComposerClient的构造函数:
 
SurfaceComposerClient::SurfaceComposerClient()
    : mStatus(NO_INIT), mComposer(Composer::getInstance())
{
}
可想而知没做啥事啊,SurfaceComposerClient 继承于RefBase类,在创建SurfaceComposerClient对象,系统第一次引用SurfaceComposerClient对象时,onFirstRef函数自动调用,我们看一下它的onFirstRef
 
void SurfaceComposerClient::onFirstRef() {
    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
    if (sm != 0) {
        sp<ISurfaceComposerClient> conn = sm->createConnection();
        if (conn != 0) {
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}

上面代码,第二行的作用是获得SurfaceFlinger这个服务,我们跟踪一下:
 
sp<ISurfaceComposer> ComposerService::getComposerService() {
    ComposerService& instance = ComposerService::getInstance();
    Mutex::Autolock _l(instance.mLock);
    if (instance.mComposerService == NULL) {
        ComposerService::getInstance().connectLocked();
        assert(instance.mComposerService != NULL);
        ALOGD("ComposerService reconnected");
    }
    return instance.mComposerService;
}
第二行得到了ComposerService的对象,是为了下一步访问它的成员变量mComposerService(ISurfaceComposer类的),跟踪到第五行的函数 connectLocked():
 
void ComposerService::connectLocked() {
    const String16 name("SurfaceFlinger");
    while (getService(name, &mComposerService) != NO_ERROR) {
        usleep(250000);
    }
    assert(mComposerService != NULL);                                                                                                         //省略了一些东西。。。
 
           }

这里看到第三行getService(),第一个参数是“SurfaceFlinger”,第二个参数是mComposerService,记住它的类型的强引用的ISurfaceComposer,对就是这句得到了一个SurfaceFlinger服务的代理对象,看一下这个的函数的实体:
template<typename INTERFACE>
status_t getService(const String16& name, sp<INTERFACE>* outService)
{
    const sp<IServiceManager> sm = defaultServiceManager();
    if (sm != NULL) {
        *outService = interface_cast<INTERFACE>(sm->getService(name));
        if ((*outService) != NULL) return NO_ERROR;
    }
    return NAME_NOT_FOUND;
}
到第四行这里跟之前启动过程中SurfaceFlinger的创建一模一样了,最后outService会被强转化成BpSurfaceComposer类,BpSurfaceComposer就是SurfaceFlinger在客户端这边的Binder代理,与之对应的是BnSurfaceComposer相当于SurfaceFlinger这边与BpSurfaceComposer进行交互的一方。获得了代理之后,我们再回到之前的onFirstRef函数:
void SurfaceComposerClient::onFirstRef() {
    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
    if (sm != 0) {
        sp<ISurfaceComposerClient> conn = sm->createConnection();
        if (conn != 0) {
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}

这时候走到if,sm有值了,所以往下走,看名字可以得出这是客户端在请求连接到SurfaceFlinger服务。我们跟踪一下createConnection:
 
virtual sp<ISurfaceComposerClient> createConnection()
    {
        uint32_t n;
        Parcel data, reply;
        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
        remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply);
        return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
    }

函数的大概意思是把一些连接信息写到数据包data里,然后通过transact这个函数传出去,remote()之前有研究过他是IBinder类的,这里重点看transact这个函数,他是IBinder类的成员函数故它的实现必定在BpBinder类里,我们跳到这个函数的实体:
 
status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    // Once a binder has died, it will never come back to life.
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}

发现他又调用了transact这个函数,不同的是 是在IPCThreadState类中的 我们继续跟踪:
status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err = data.errorCheck();

    flags |= TF_ACCEPT_FDS;

    IF_LOG_TRANSACTIONS() {
        TextOutput::Bundle _b(alog);
        alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
            << handle << " / code " << TypeCode(code) << ": "
            << indent << data << dedent << endl;
    }
    
    if (err == NO_ERROR) {
        LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
            (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    }
    
    if (err != NO_ERROR) {
        if (reply) reply->setError(err);
        return (mLastError = err);
    }
    
    if ((flags & TF_ONE_WAY) == 0) {
        #if 0
        if (code == 4) { // relayout
            ALOGI(">>>>>> CALLING transaction 4");
        } else {
            ALOGI(">>>>>> CALLING transaction %d", code);
        }
        #endif
        if (reply) {
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
        #if 0
        if (code == 4) { // relayout
            ALOGI("<<<<<< RETURNING transaction 4");
        } else {
            ALOGI("<<<<<< RETURNING transaction %d", code);
        }
        #endif
        
        IF_LOG_TRANSACTIONS() {
            TextOutput::Bundle _b(alog);
            alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
                << handle << ": ";
            if (reply) alog << indent << *reply << dedent << endl;
            else alog << "(none requested)" << endl;
        }
    } else {
        err = waitForResponse(NULL, NULL);
    }
    
    return err;
}

这里已经扯到Binder机制的基本原理了,简单说就是客户端的SF代理通过BpBinder跟/dev/binder设备进行交互,向binder里写东西,函数err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);就是实现了这个功能,写完后他又等待服务端(SurfaceFlinger)那端的回应,err = waitForResponse(reply);当然服务端那边同样有人跟他进行交互。到这里,如果服务端收到消息并且返回了一个消息给客户端,这说明客户端请求连接成功。

     请求成功后conn就不为0了,回到onFirstRef,成功后把coon赋给mClient。

既然客户端有请求了,那么服务端肯定有东西会去留意这个消息,回到更以前,做出向服务端请求连接这件事其实是SurfaceFlinger在客户端这边的代理BpSurfaceComposer完成的,那么之前说过,与之对应的就是BnSurfaceComposer。我们看一下他类的定义:

 

class BnSurfaceComposer: public BnInterface<ISurfaceComposer> {
public:
    enum {
        // Note: BOOT_FINISHED must remain this value, it is called from
        // Java by ActivityManagerService.
        BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
        CREATE_CONNECTION,
        CREATE_GRAPHIC_BUFFER_ALLOC,
        CREATE_DISPLAY_EVENT_CONNECTION,
        CREATE_DISPLAY,
        DESTROY_DISPLAY,
        GET_BUILT_IN_DISPLAY,
        SET_TRANSACTION_STATE,
        AUTHENTICATE_SURFACE,
        BLANK,
        UNBLANK,
        GET_DISPLAY_INFO,
        CONNECT_DISPLAY,
        CAPTURE_SCREEN,
    };

    virtual status_t onTransact(uint32_t code, const Parcel& data,
            Parcel* reply, uint32_t flags = 0);
 }

发现他没有构造函数只有一个成员函数 onTransact。跟踪一下:

status_t BnSurfaceComposer::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code) {
        case CREATE_CONNECTION: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            sp<IBinder> b = createConnection()->asBinder();
            reply->writeStrongBinder(b);
            return NO_ERROR;
        }
        case CREATE_GRAPHIC_BUFFER_ALLOC: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            sp<IBinder> b = createGraphicBufferAlloc()->asBinder();
            reply->writeStrongBinder(b);
            return NO_ERROR;
        }
        case SET_TRANSACTION_STATE: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            size_t count = data.readInt32();
            ComposerState s;
            Vector<ComposerState> state;
            state.setCapacity(count);
            for (size_t i=0 ; i<count ; i++) {
                s.read(data);
                state.add(s);
            }
            count = data.readInt32();
            DisplayState d;
            Vector<DisplayState> displays;
            displays.setCapacity(count);
            for (size_t i=0 ; i<count ; i++) {
                d.read(data);
                displays.add(d);
            }
            uint32_t flags = data.readInt32();
            setTransactionState(state, displays, flags);
            return NO_ERROR;
        }
        case BOOT_FINISHED: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            bootFinished();
            return NO_ERROR;
        }
        case CAPTURE_SCREEN: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            sp<IBinder> display = data.readStrongBinder();
            sp<IGraphicBufferProducer> producer =
                    interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
            uint32_t reqWidth = data.readInt32();
            uint32_t reqHeight = data.readInt32();
            uint32_t minLayerZ = data.readInt32();
            uint32_t maxLayerZ = data.readInt32();
            status_t res = captureScreen(display, producer,
                    reqWidth, reqHeight, minLayerZ, maxLayerZ);
            reply->writeInt32(res);
            return NO_ERROR;
        }
        case AUTHENTICATE_SURFACE: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            sp<IGraphicBufferProducer> bufferProducer =
                    interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
            int32_t result = authenticateSurfaceTexture(bufferProducer) ? 1 : 0;
            reply->writeInt32(result);
            return NO_ERROR;
        }
        case CREATE_DISPLAY_EVENT_CONNECTION: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            sp<IDisplayEventConnection> connection(createDisplayEventConnection());
            reply->writeStrongBinder(connection->asBinder());
            return NO_ERROR;
        }
        case CREATE_DISPLAY: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            String8 displayName = data.readString8();
            bool secure = bool(data.readInt32());
            sp<IBinder> display(createDisplay(displayName, secure));
            reply->writeStrongBinder(display);
            return NO_ERROR;
        }
        case DESTROY_DISPLAY: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            sp<IBinder> display = data.readStrongBinder();
            destroyDisplay(display);
            return NO_ERROR;
        }
        case GET_BUILT_IN_DISPLAY: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            int32_t id = data.readInt32();
            sp<IBinder> display(getBuiltInDisplay(id));
            reply->writeStrongBinder(display);
            return NO_ERROR;
        }
        case BLANK: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            sp<IBinder> display = data.readStrongBinder();
            blank(display);
            return NO_ERROR;
        }
        case UNBLANK: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            sp<IBinder> display = data.readStrongBinder();
            unblank(display);
            return NO_ERROR;
        }
        case GET_DISPLAY_INFO: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            DisplayInfo info;
            sp<IBinder> display = data.readStrongBinder();
            status_t result = getDisplayInfo(display, &info);
            memcpy(reply->writeInplace(sizeof(DisplayInfo)), &info, sizeof(DisplayInfo));
            reply->writeInt32(result);
            return NO_ERROR;
        }
        default: {
            return BBinder::onTransact(code, data, reply, flags);
        }
    }
    // should be unreachable
    return NO_ERROR;
}

代码虽然有点长,但是整体框架就是一个swith语句,看到第一个分支,马上就能看出来这是一个对请求连接信号的处理,这里大概能知道这个onTransact的功能就是判断收到的消息即参数code是哪种类型从而做出相应的处理。在server测,一开始创建SF服务的时候,在线城池创建的时候就已经开启线程去监听binder设备了我们来跟踪下:

 从最开始SF服务启动的源文件开始:

int main(int argc, char** argv) {
    // When SF is launched in its own process, limit the number of
    // binder threads to 4.
    ProcessState::self()->setThreadPoolMaxThreadCount(4);

    // start the thread pool
    sp<ProcessState> ps(ProcessState::self());
    ps->startThreadPool();

是一个片段,最后一句就是开始线程池。跟踪其代码:

void ProcessState::startThreadPool()
{
    AutoMutex _l(mLock);
    if (!mThreadPoolStarted) {
        mThreadPoolStarted = true;
        spawnPooledThread(true);
    }
}

核心也在最后一句,

void ProcessState::spawnPooledThread(bool isMain)
{
    if (mThreadPoolStarted) {
        String8 name = makeBinderThreadName();
        ALOGV("Spawning new pooled thread, name=%s\n", name.string());
        sp<Thread> t = new PoolThread(isMain);
        t->run(name.string());
    }
}


到这里,可以看到实质的线程创建和开始运行。接下来我用一张图来表示他的函数调用的走向:

这里一旦检测到有连接请求消息就会跳到executeCommand的switch分支BR_TRANSACTION,去执行BBinder的transact,transact函数会调用onTransact函数,这个onTransact由其子类实现,在这里由BnSurfaceComposer完成,即调用的是BnSurfaceComposer::onTransact(),函数的具体内容在上面已贴出,就是处理不同的请求。

     到此为止,客户端已经与SF进行连接,也就是交手过了,那么自然连接了,一定要做些事情比如客户端请求渲染一个surface,或者等等其他的。接下去的工作就是SurfaceFlinger的事,对客户端不同的请求而进行不同的处理,这才是SF核心工作所在。当然所有的通信机制都是基于binder机制,而求也有负责这个方面的客户端这边的binder代理BpSurfaceComposerClient和服务端这边的本地对象 BnSurfaceComposerClient,而这里有点不一样的是BnSurfaceComposerClient派生出Client所以事情都交与Client做了。


 




 

 
 
      


 
 
 
 
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android4.4深入浅出之SurfaceFlinger与Client通信框架(一) 的相关文章

随机推荐

  • Springboot @Lazy注解

    作者 小猿聊编程 更多资料 https www techlearn cn 作用 Lazy可以实现bean的延迟初始化 在spring容器启动时不初始化Bean 直到用到这个Bean的时候才去初始化 使用范围 任意类型 方法 构造器 参数 字
  • Unity 检测物体是否在屏幕内

  • sql查询无结果设置默认值

    笔记 最近SQL直挂图表数据显示无内容 看了下数据库发现表里没数据 三方图表默认显示文字 但是需求想显示结果0 所以要想办法把无结果得数据默认给一个默认值 查询字段通常分为 null两种 前提是有结果 但是字段可能没数据 用case whe
  • Eclipse Svn插件各个版本以及对应Svn Connector的下载地址

    Eclipse Svn插件各个版本以及对应Svn Connector的下载地址 http www polarion com products svn subversive download php 可供大家把包下载然后在Eclipse里面进
  • linux内核新版gpio配置

    新版gpio操作
  • 2019年第十届蓝桥杯真题解析

    难度 难 算法 二分法 问题描述 小明公司的办公区有一条长长的走廊 由 N 个方格区域组成 如下图所示 走廊内部署了 K 台扫地机器人 其中第 i 台在第 Ai 个方格区域中 已知扫地机器人每分钟可以移动到左右相邻的方格中 并将该区域清扫干
  • 一键清空朋友圈软件_微信清理朋友圈app下载-微信清理朋友圈下载v1.8.0 安卓版-西西软件下载...

    微信清理朋友圈app一款强大的微信清理工具 当你想要重置自己的微信号并删除所有的内容之时 又觉得一条条删太麻烦了 就可以用到这款神器工具 可以帮助你一键删除掉朋友圈内的所有内容 帮助你轻松的重置微信号 十分的方便 赶快下载微信清理朋友圈ap
  • CentOS系统性能工具 sar 示例!

    安装配置 Sysstat 安装 Sysstat 包 Ubuntu sudo apt get install sysstat CentOS yum install sysstat CentOS rpm ivh sysstat 10 0 0 1
  • 使用FFmpeg进行屏幕录像和录音

    有些时候我们需要对屏幕进行录制 比如制作视频教程 录制直播等 然而这方面的软件多是收费的 即使是免费试用版的还有水印 特别烦人 下面介绍使用FFmpeg进行屏幕录制的方法 Windows 先安装dshow软件 Screen Capturer
  • iOS推送(利用极光推送)

    本文主要是基于极光推送的SDK封装的一个快速集成极光推送的类的封装 不喜勿喷 1 首先说一下推送的一些原理 Push的原理 Push 的工作机制可以简单的概括为下图图中 Provider是指某个iPhone软件的Push服务器 这篇文章我将
  • Linux SSH登录服务器报ECDSA host key “ip地址“ for has changed and you have requested strict checking错误

    Linux SSH命令用了那么久 第一次遇到这样的错误 ECDSA host key ip地址 for has changed and you have requested strict checking 记录下方便记忆 解决方案 在终端上
  • 系统没有wmi服务器,系统没有WMI服务怎么办.WMI错误修复方法

    WMI是一项核心的Windows管理技术 WMI作为一种规范和基础结构 通过它可以访问 配置 管理和监视几乎所有的Windows资源 比如用户可以在远程计算机器上启动一个进程 设定一个在特定日期和时间运行的进程 远程启动计算机 获得本地或远
  • XCTF_Web_新手练习区:simple_js(源代码详解)

    文章目录 第七题 simple js 源代码详解 目标 Writeup 源代码详解 第七题 simple js 源代码详解 目标 掌握有关js的知识 Writeup 进入环境后我们遇到了输入密码 于是我们随便输入一个密码 点击确定 之后啥也
  • Android应用底部导航栏(选项卡)实例

    现在很多android的应用都采用底部导航栏的功能 这样可以使得用户在使用过程中随意切换不同的页面 现在我采用TabHost组件来自定义一个底部的导航栏的功能 我们先看下该demo实例的框架图 其中各个类的作用以及资源文件就不详细解释了 还
  • 十分钟利用windows7漏洞破解开机密码

    所有win7系统都使用 首先连按五下Shift键弹出粘滞键提醒 然后我们点击否后关机 启动系统时将其强制关机 虚拟机利用电源关闭虚拟机 自用主机就在开机时长按关机键强制关闭系统 随后启动系统 我们选择启动启动修复 推荐 选择取消即不还原 等
  • Python数据可视化——折线图

    Python数据可视化 折线图 随着数据分析和数据科学的飞速发展 数据可视化成为了越来越重要的一环 而Python作为一门强大的编程语言 其在数据可视化领域也有着不俗的表现 本文将为大家介绍如何使用Python的Matplotlib库创建一
  • 【Transformers】第 6 章:用于标记分类的微调语言模型

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • Vue.config.js常用配置详解

    摘要 本文将介绍Vue config js中常用的配置选项 包括publicPath outputDir devServer chainWebpack等 并提供相应的代码示例 帮助读者更好地理解和配置Vue项目 1 publicPath p
  • 新汽车电子技术图谱

    商业模式 改变传统对于OEM来讲的 卖车即结束 的模式 会员模式 共享模式 租赁模式 运营模式等各种新型的数字出行体验模式 OTA云 远程刷新 远程诊断 远程车控 远程数据上传 第三方App 应用商店 边缘计算 多级云计算 大数据处理 AI
  • Android4.4深入浅出之SurfaceFlinger与Client通信框架(一)

    SurfaceFlinger框架是基于Binder进程间通信机制搭建的 SF作为一个服务进程 用户程序想要跟它通信必然要经过Binder机制 首先说一下 用户要跟SF通信 那么SF必须出现在ServiceManager中 因为SF也是一个服