SurfaceFlinger模块

2023-05-16

SurfaceFlinger是一个系统服务,作用就是接受不同layer的buffer数据进行合成,然后发送到显示设备进行显示。

SurfaceFlinger进程是什么时候起来的?

在之前的Android低版本手机上,SurfaceFlinger进程是在init.rc中启动的,在最新的高版本上SurfaceFlinger进程并不是直接在init.rc文件中启动的,而是通过Android.bp去启动surfaceflinger.rc文件,然后解析文件内容启动SurfaceFlinger进程。

/framework/native/services/surfaceflinger/surfaceflinger.rc

service surfaceflinger /system/bin/surfaceflinger
    class core animation
    user system
    group graphics drmrpc readproc
    capabilities SYS_NICE
    onrestart restart zygote
    task_profiles HighPerformance
    socket pdx/system/vr/display/client     stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
    socket pdx/system/vr/display/manager    stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
    socket pdx/system/vr/display/vsync      stream 0666 system graphics u:object_r:pdx_display_vsync_endpoint_socket:s0
关于init.rc文件的解析和Android.bp编译脚本的执行本文不做深入研究,启动SurfaceFlinger进程,就会执行到main函数。

/services/surfaceflinger/Main_surfaceflinger.cpp
关于main函数中,有几个关键的点需要关注。

  1. ProcessState::self() 函数的调用,个人理解是同binder驱动建立链接,获取驱动的版本,通知驱动,同时启动线程来处理Client的请求,总结如下:
    (1)构建ProcessState全局对象gProcess
    (2)打开binder驱动,建立链接
    (3)在驱动内部创建该进程的binder_proc,binder_thread结构,保存该进程的进程信息和线程信息,并加入驱动的红黑树队列中。
    (4)获取驱动的版本信息
    (5)把该进程最多可同时启动的线程告诉驱动,并保存到改进程的binder_proc结构中
    (6)把设备文件/dev/binder映射到内存中

  2. 设置SurfaceFlinger进程的优先级

    关于cpuset的使用,有一些简单的命令如下:

    查看cpuset的所有分组
    adb shell ls -l /dev/cpuset

    查看system-background的cpuset的cpu
    adb shell cat /dev/cpuset/system-background/cpus

    查看system-background的应用
    adb shell cat /dev/cpuset/system-background/tasks

    查看SurfaceFlinger的cpuset
    adb shell 'cat /proc/(pid of surfaceflinger)/cpuset'

  3. setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
    set_sched_policy(0, SP_FOREGROUND);
    if(cpusets_enabled()){
        set_cpuset_policy(0, SP_SYSTEM);
    }

可以自定义cpuset,就是可以根据各自的需求,动态配置自定义的cpuset,例如SurfaceFlinger的线程默认跑到4个小核上,假如有个需求要把SurfaceFlinger的线程跑到大核上,就可以配置自定义cpuset,在进入某个场景的时候,把SurfaceFlinger进程pid配置到自定义的cpuset的tasks中。

3 初始化SurfaceFlinger

// 实例化 SurfaceFlinger
sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger();
// 初始化 SurfaceFlinger
flinger->init();
// 将 SurfaceFlinger添加到 ServiceManager 进程中
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false, IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
//启动 DisplayService
startDisplayService();
// 启动 SurfaceFlinger
flinger->run();

实例化 SurfaceFlinger

有个SurfaceFlingerFactory.cpp,设计模式中的工厂类,在该头文件中定义了好多创建不同对象的函数。
/frameworks/native/services/surfaceflinger/SurfaceFlingerFactory.cpp

sp<SurfaceFlinger> createSurfaceFlinger() {
    static DefaultFactory factory;
    return new SurfaceFlinger(factory);
}

通过createSurfaceFlinger()方法创建了一个SurfaceFlinger对象。

/frameworks/native/services/surfaceflinger/SurfaceFlinger.h

class SurfaceFlinger : public BnSurfaceComposer,
                       public PriorityDumper,
                       private IBinder::DeathRecipient,
                       private HWC2::ComposerCallback,
                       private ISchedulerCallback

SurfaceFlinger继承BnSurfaceComposer,实现ISurfaceComposer接口,实现ComposerCallback,PriorityDumper是一个辅助类,提供了SurfaceFlinger的dump信息。

关于ISurfaceComposer的接口定义和实现,本文不做细节描述。

outside_default.png

image-20220506103643934.png

  1. ISurfaceComposer 是Client端对SurfaceFlinger进程的binder接口调用。

  2. ComposerCallback,这个是HWC模块的回调,这个包含了三个很关键的回调函数,onComposerHotplug函数表示显示屏热插拔事件, onComposerHalRefresh函数表示Refresh事件,onComposerHalVsync表示Vsync信号事件。

接下来分析SurfaceFlinger的构造函数。

在SurfaceFlinger中的构造方法中,初始化了很多全局变量,有一些变量会直接影响整个代码的执行流程,而这些变量都可以在开发者模式中去更改它,SurfaceFlinger作为binder的服务端,设置应用中的开发者模式做为Client端进行binder调用去设置更改,主要是为了调试测试,其中还包含芯片厂商高通的一些辅助功能。

初始化 SurfaceFlinger


实例化SurfaceFlinger对象之后,调用init方法,这个方法有几个比较重要的代码。

  1. 构造SkiaRenderEngine渲染引擎

mCompositionEngine->setRenderEngine(renderengine::RenderEngine::create(
        renderengine::RenderEngineCreationArgs::Builder()
                .setPixelFormat(static_cast<int32_t>(defaultCompositionPixelFormat))
                .setImageCacheSize(maxFrameBufferAcquiredBuffers)
                .setUseColorManagerment(useColorManagement)
                .setEnableProtectedContext(enable_protected_contents(false))
                .setPrecacheToneMapperShaderOnly(false)
                .setSupportsBackgroundBlur(mSupportsBlur)
                .setContextPriority(
                        useContextPriority
                                ? renderengine::RenderEngine::ContextPriority::REALTIME
                                : renderengine::RenderEngine::ContextPriority::MEDIUM)
                .build()));

在Android S版本之前,这块的绘制流程都是OpenGL ES实现的,在Android S版本上这块逻辑已经切换到Skia库进行绘制,mCompositionEngine这个类比较重要,主要负责Layer的Client合成,Client合成就是GPU合成。目前Layer的合成方式有两种,一个是GPU合成,一个是HWC合成,针对Skia库的研究有单独的章节进行讲解。

  1. 构造Vsync

    // Process any initial hotplug and resulting display changes.
    processDisplayHotplugEventsLocked();

在init方法中,重点看这个函数中调用了initScheduler方法。

// start the EventThread
mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this);
const auto configs = mVsyncConfiguration->getCurrentConfigs();
const nsecs_t vsyncPeriod = currRefreshRate.getPeriodNsecs();
mAppConnectionHandle =
        mScheduler->createConnection("app", mFrameTimeline->getTokenManager(),
                                     /*workDuration=*/configs.late.appWorkDuration,
                                     /*readyDuration=*/configs.late.sfWorkDuration,
                                     impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
        mScheduler->createConnection("appSf", mFrameTimeline->getTokenManager(),
                                     /*workDuration=*/std::chrono::nanoseconds(vsyncPeriod),
                                     /*readyDuration=*/configs.late.sfWorkDuration,
                                     [this](nsecs_t timestamp) {
                                         mInterceptor->saveVSyncEvent(timestamp);
                                     });


mEventQueue->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(),
                       configs.late.sfWorkDuration);

图中是initScheduler方法中几个关键的代码,该代码和Vsync研究密切相关,当分析研究SurfaceFlinger的合成流程,也就最核心的流程,其触发条件就是由Vsync控制的,Vsync很像一个节拍器,SurfaceFlinger中每一帧的合成都需要跟随节拍器,太快或者太慢都会导致屏幕显示异常,一般表现为画面卡顿,不流畅,关于Vsync的研究有独立章节进行讲解。

  1. 举例讲解一个init函数中高通一个so库的加载

char layerExtProp[PROPERTY_VALUE_MAX];
property_get("vendor.display.use_layer_ext", layerExtProp, "0");
if(atoi(layerExtProp)){
    mUseLayerExt = true;
}

当把vendor.display.use_layer_ext中配置成1,就会把mUseLayerExt的变量置为true,这个变量代表SurfaceFlinger使用liblayerext.qti.so。这个so库是判断当前的Layer是不是游戏的Layer,当这个库加载成功之后,BufferLayer在构造函数中初始化mLayerClass的变量。

if(mFlinger->mLayerExt){
    mLayerClass = mFlinger -> mLayerExt ->GetLayerClass(mName);
}

当mLayerClass被初始化成功之后,第三方应用可以通过binder调用,查询SurfaceFlinger进程这个应用的Layer是不是游戏的Layer。在最新的Android S版本有个AppClassifierApk应用需要启动,如果被禁止会导致Layer类型判断出现问题,这个应用是高通实现的,也是闭源的,它会监听应用的安装广播,在数据库中记录安装应用的类别信息。鉴于芯片厂商植入的功能很多时候都会造成性能问题,默认都会关闭掉。

  1. 将SurfaceFlinger添加到 ServiceManager进程中

SurfaceFlinger模块提供很多binder接口,在服务端的onTransact函数会根据Client端传递的code做不同的代码处理,下图是onTransact函数中一处code的处理。

case 1034: {
    switch (n = data.readInt32()) {
        case 0:
        case 1:
            enableRefreshRateOverlay(static_cast<bool>(n));
            break;
        default: {
            Mutex::Autolock lock(mStateLock);
            reply->writeBool(mRefreshRateOverlay != nullptr);
        }
    }
    return NO_ERROR;
}

这个code是1034的逻辑,是那个Client端调用过来的呢?

是设置应用中的开发者模式页面中的功能,搜索了Settings应用中关于1034的逻辑,找到了一处代码包含这段逻辑。

/Settings/src/com/android/settings/development/ShowRefreshRatePreferenceController.java

private static final String SHOW_REFRESH_RATE_KEY = "show_refresh_rate";
@VisibleForTesting
static final int SURFACE_FLINGER_CODE = 1034;
public ShowRefreshRatePreferenceController(Context context) {
    super(context);
    mSurfaceFlinger = ServiceManager.getService(SURFACE_FLINGER_SERVICE_KEY);
}
@VisibleForTesting
void updateShowRefreshRateSetting() {
    // magic communication with surface flinger.
    try {
        if (mSurfaceFlinger != null) {
            final Parcel data = Parcel.obtain();
            final Parcel reply = Parcel.obtain();
            data.writeInterfaceToken(SURFACE_COMPOSER_INTERFACE_KEY);
            data.writeInt(SETTING_VALUE_QUERY);
            mSurfaceFlinger.transact(SURFACE_FLINGER_CODE, data, reply, 0 /* flags */);
            final boolean enabled = reply.readBoolean();
            ((SwitchPreference) mPreference).setChecked(enabled);
            reply.recycle();
             data.recycle();
         }
     } catch (RemoteException ex) {
         // intentional no-op
     }
 }

从上面的代码可以看到,App端对SurfaceFlinger进程进行了binder通讯。

  1. 启动 SurfaceFlinger

void SurfaceFlinger::run() {
    while (true) {
        mEventQueue->waitMessage();
    }
}
void SurfaceFlinger::onFirstRef() {
    mEventQueue->init(this);
}

在前面介绍的main函数,SurfaceFlinger对象是一个智能指针,sp强引用指针。该智能指针在第一次引用的时候,会调用onFirstRef方法,进一步实例化内部需要的对象,这个方法调用了mEventQueue的init方法,而这个对象就是线程安全的MessageQueue对象。

SurfaceFlinger中的MessageQueue和Android应用层开发的MessageQueue设计非常相似,只是个别角色做的事情稍微有一点不同。

SurfaceFlinger的MessageQueue机制的角色:

  1. MessageQueue 同样做为消息队列向外暴露接口,不像应用层的MessageQueue一样作为Message链表的队列缓存,而是提供了相应的发送消息的接口以及等待消息方法。

  2. native的Looper是整个MessageQueue的核心,以epoll_event为核心,event_fd为辅助构建一套快速的消息回调机制。

  3. native的Handler则是实现handleMessage方法,当Looper回调的时候,将会调用Handler中的handleMessage方法处理回调函数。

MessageQueue init

/frameworks/native/services/surfaceflinger/Scheduler/MessageQueue.cpp

void MessageQueue::init(const sp<SurfaceFlinger>& flinger) {
    mFlinger = flinger;
    mLooper = new Looper(true);
    mHandler = new Handler(*this);
}

该init方法中实例化了Looper和Handle。

void MessageQueue::Handler::handleMessage(const Message& message) {
    switch (message.what) {
        case INVALIDATE:
            mEventMask.fetch_and(~eventMaskInvalidate);
            mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime);
            break;
        case REFRESH:
            mEventMask.fetch_and(~eventMaskRefresh);
            mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime);
            break;
    }
}

在上面的回调函数,可以看到注册了两种不同的刷新监听,一个是invalidate刷新,一个是refresh刷新。它们最后都会回调到SurfaceFlinger中的onMessageReceived中,换句话说,每当我们需要图元刷新的时候,就会通过mEventQueue的post方法,回调到SurfaceFlinger的主线程进行合成刷新。

以上就是SurfaceFlinger进程初始化的过程,中间提到了一些比较重要的类或者对象,接下来会通过几个章节对SurfaceFlinger进程中比较核心的逻辑进行代码讲解。

  1. 第1章 Vsync研究

  2. 第2章 BufferQueue研究

  3. 第3章 SurfaceFlinger动画研究

  4. 第4章 SurfaceFlinger主流程研究

  5. 第5章 HWC研究

  6. 第6章 Android显示流程研究

  7. 第7章 Skia库研究

  8. 第8章 截图/录屏流程研

作者:努比亚技术团队
链接:https://www.jianshu.com/p/db6f62f70ed1

关注我获取更多知识或者投稿

5d9c9ff20d263af95633142a96772834.jpeg

82f1ff548e94d2555963a27c346ecda6.jpeg

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

SurfaceFlinger模块 的相关文章

  • 初学FreeRTOS实现多任务程序

    初学FreeRTOS实现多任务程序 1 什么是FreeRTOS2 STM32下FreeRTOS移植2 1 准备工作2 2 移植更改2 2 1 新建分组2 2 2 添加相应的头文件路径2 2 3 修改 SYSTEM 文件 3 多任务程序的实现
  • 【计网+go】如何获取完整的报文?

    我们想要获取完整的报文 xff0c 首先得知道消息的长度和起始位置然后来读取 通常有以下几种方法 使用带消息头的协议 头部写入包长度 xff0c 然后再读取包内容 设置定长消息 xff0c 每次读取定长内容 xff0c 长度不够时空位补固定
  • Visual Studio 2022下载安装

    Visual Studio 2022下载安装 1 进入官网 官网地址 xff1a https visualstudio microsoft com 这里以Windows操作系统为例 根据需要选择版本 xff0c 我这里下载的是Enterpr
  • Lighttpd入门教程

    Lighttpd入门教程 概述入门教程安装配置静态文件服务动态文件服务 虚拟主机SSL启动服务器日志模块总结lighthttpd使用场景和原理使用场景原理 概述 Lighttpd xff08 也称为轻量级HTTP服务器 xff09 是一款快
  • 5.OSD叠加学习之在YUV图片上显示 竖线横线斜线

    目录 实现效果图 实现思路 xff1a 代码编写 实现效果图 实现思路 xff1a 无论是显示 竖线横线还是斜线 xff0c 无非是对 多个连续的 像素点进行操作 xff0c 明白了一个像素点如何点亮 xff0c 加个循环偏移量 xff0c
  • shell脚本发送http请求

    简述 xff1a 使用shell脚本发送http请求 xff0c 解析请求获取token再次发起请求 系统 xff1a ubuntu系统 工具 xff1a cURL 发送http请求 xff0c jq 解析json xff0c 没有需要安装
  • 2020年电赛省赛题目A——无线运动传感器节点设计

    无线运动传感器节点设计 题目要求设计方案分析心电检测模块方案ADS1292的A D转换计算心电信号的处理体表温度分析计算运动量分析计算无线传输模块设计显示屏的设计电路设计温度模块设计加速度计模块设计无线传输模块设计PCB布线布局 题目要求
  • 【全志T113-S3_100ask】8-USB串口获取GPS数据(含解析)

    全志T113 S3 100ask 8 USB串口获取GPS数据 xff08 含解析 xff09 背景 xff08 一 xff09 USB串口驱动 xff08 二 xff09 驱动加载 xff08 三 xff09 简单读取串口数据 xff08
  • Java ---JVM栈的存储结构与运行原理

    目录 一 栈中存储结构 二 栈运行原理 一 栈中存储结构 1 每个线程都有自己的栈 xff0c 栈中的数据都是以栈帧 Stack Frame 的格式存在 2 在这个线程上正在执行的每个方法都各自对应一个栈帧 3 栈帧是一个内存区块 xff0
  • c++配置opencv环境

    c 43 43 配置opencv环境 环境 xff1a 系统 xff1a win10系统截至20190523版本 opencv版本 xff1a 3 4 6版本 教程 xff1a 1 下载opencv安装包 xff0c 由于4 0 1版本会出
  • Android应用安全解决方案

    前言 防止第三方反编译篡改应用 xff0c 防止数据隐私泄露 xff0c 防止二次打包欺骗用户 1 一些必要的基础知识 我们在加密的时候会用到一些加密或者编码方法 常见的有 xff0c 非对称加密算法 RSA 等 xff1b 对称加密算法
  • win10修改系统配置处理器引导参数后,系统无限蓝屏解决办法

    win10修改系统配置处理器引导参数后 xff0c 系统无限蓝屏解决办法 0 xff1a 开机时先按f8进入安全模式 xff0c 在进入命令提示符 1 进入 启动修复 的 命令提示符 xff08 最好是使用有管理员权限的 xff0c 不过普
  • 运行内存变成的2G,为硬件保留内存为6G

    运行内存变成的2G xff0c 为硬件保留内存为6G 先看设置中下面是否有设置是否激活windows xff0c 如有点进去 xff0c 有疑难解疑下面 xff0c 点入会自动激活windows xff0c 如盗版就不行 xff0c 激活后

随机推荐

  • ubuntu20.4安装NVIDIA驱动,cuda

    安装NVIDIA驱动准备工作 下载NVIDIA地址 xff1a https www nvidia cn Download index aspx lang 61 cn 查看是否安装好驱动命令 xff1a nvidia span class t
  • 图像进行反转:白变黑,黑变白

    图像进行反转 xff1a 白变黑 xff0c 黑变白 二值图对图像进行反转 span class token keyword import span cv2 img span class token operator 61 span spa
  • python调用相机和双目相机

    python调用相机 span class token keyword import span cv2 span class token keyword import span numpy span class token keyword
  • 安装PCL1.9.1其它版本号Python3.6+PCL1.9.1+VS2017+gtkbundle_3.6.4版本

    下载 python pcl文件 地址 xff1a https github com strawlab python pcl 安装 VS2017 安装PLC1 91 首先在自己电脑上安装PCL xff08 点击这里 xff09 xff0c 这
  • ROS--机器人小车仿真rviz

    URDF练习 需求描述 创建一个四轮圆柱状机器人模型 xff0c 机器人参数如下 底盘为圆柱状 xff0c 半径 10cm xff0c 高 8cm xff0c 四轮由两个驱动轮和两个万向支撑轮组成 xff0c 两个驱动轮半径为 3 25cm
  • ROS--URDF集成Gazebo仿真小车和rviz结合

    ROS URDF集成Gazebo仿真小车 实现流程 需要编写封装惯性矩阵算法的 xacro 文件 为机器人模型中的每一个 link 添加 collision 和 inertial 标签 xff0c 并且重置颜色属性 在 launch 文件中
  • 使用D435i深度相机运行ORB-SLAM3

    下载安装链接 下载ORB SLAM3地址 xff1a git clone https github com UZ SLAMLab ORB SLAM3 git eigen3多版本安装 xff1a https blog csdn net wei
  • keil5使用一个父工程打开多个子工程文件

    1 首先工程文件需要在同样的文件夹里 2 打开keil5 xff0c 选择Project New Multi Project Workspace 3 将工程文件建立在刚刚的总文件夹里面 xff0c 命名保存 4 弹出此页面 xff08 Cr
  • ​Android动态加载so!这一篇就够了!

    作者 xff1a Pika 链接 xff1a https juejin cn post 7107958280097366030 对于一个普通的android应用来说 xff0c so库的占比通常都是巨高不下的 xff0c 因为我们无可避免的
  • HTTP是什么

    HTTP是什么 HTTP是什么 HTTP协议是Hyper Text Transfer Protocol xff08 超文本传输协议 xff09 的缩写 是用于从万维网 xff08 WWW World Wide Web xff09 服务器传输
  • error: array has incomplete element type ‘char []‘

    原代码 xff1a void explain input char int char a 报错 xff1a error array has incomplete element type 39 char 39 原因 xff1a 可以用二维数
  • STM32串口接收十六进制数转为十进制数(包含负数)

    外部设备传输给STM32单片机十六进制数 例如0x09c4 代表2500 0xff38 代表 200 xff08 并不是65336 xff0c 因为这是有符号的 xff09 串口接收处理函数 接收到 5A A5 06 83 55 00 01
  • 无人机-3无人机ROS应用与开发

    一 ROS是什么 二 为什么要学习ROS 三 怎么学习ROS https www cnblogs com masbay p 10745170 html TF坐标系指机器人在现实世界会有坐标的变换 xff0c ROS已经将其算成固定的程序 x
  • ROS入门-4.安装ROS系统(ubuntu20.04版本安装ros的noetic版本)

    ubuntu20 04版本安装ros的noetic版本 1 添加软件源2 添加密钥3 更新4 安装ROS5 初始化rosdep6 设置环境变量7 测试ROS安装是否成功 1 添加软件源 2 添加密钥 3 更新 4 安装ROS 5 初始化ro
  • 数学建模-12.预测模型

    灰色预测 灰色系统 GM 1 1 模型 xff1a Grey Model GM 1 1 原理介绍 呢么 xff0c 准指数规律的检验 xff1f 发展系数 a 与预测情形的探究 发展系数越小预测的越精确 GM 1 1 模型的评价 在使用GM
  • 数学建模-数学规划模型

    数学规划模型 一 概述 1 什么是数学规划 xff1f 运筹学的一个分支 xff0c 用来研究在给定条件下 即约束条件 xff0c 如何按照某一衡量指标 xff08 目标函数 xff09 来寻求计划 管理工作中的最优方案 即求目标函数在一定
  • 机器学习西瓜书学习记录-第四章 决策树

    第4章 决策树 4 1基本流程 决策树 xff0c 一类常见机器学习方法 xff0c 希望从给定训练集学得一个模型用以对新示例进行分类 一般 xff0c 一棵决策树包含一个根结点 若干个内部结点和若干个叶结点 xff1b 叶结点对应于决策结
  • 机器学习西瓜书学习记录-第五章 神经网络

    第5章 神经网络 5 1神经元模型 神经网络中最基本的成分是神经元模型 M P神经元模型 xff0c 又称 阈值逻辑单元 在模型中 xff0c 神经元接收到来自n个其他神经元传递过来的输入信号 xff0c 这些输入信号通过带权重的连接进行传
  • 机器学习西瓜书学习记录-第六章 支持向量机

    第6章 支持向量机 移步b站学习 学习贴
  • SurfaceFlinger模块

    SurfaceFlinger是一个系统服务 xff0c 作用就是接受不同layer的buffer数据进行合成 xff0c 然后发送到显示设备进行显示 SurfaceFlinger进程是什么时候起来的 xff1f 在之前的Android低版本