Android图形系统(十)-SurfaceFlinger启动及图层合成送显过程

这个系列最后一篇文章,简单总结下SurfaceFlinger的启动流程及合成视图过程。

一、SurfaceFlinger启动流程

SurfaceFlinger 进程是由 init 进程创建的,运行在独立进程中。

//init.rc
service surfaceflinger /system/bin/surfaceflinger
    class core
    user system
    group graphics drmrpc
    onrestart restart zygote
    writepid /dev/cpuset/system-background/tasks

SurfaceFlinger 的创建会执行 main() 方法:

//main_surfaceflinger.cpp
int main(int, char**) {
    ProcessState::self()->setThreadPoolMaxThreadCount(4);
    sp<ProcessState> ps(ProcessState::self());
    ps->startThreadPool();
    //实例化 surfaceflinger
    sp<SurfaceFlinger> flinger =  new SurfaceFlinger();
    setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
    set_sched_policy(0, SP_FOREGROUND);
    //初始化
    flinger->init();
    //发布 surface flinger,注册到 ServiceManager
    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);
    // 运行在当前线程
    flinger->run();
    return 0;
}

事实上到这里,SurfaceFlinger进程就已经启动了。之后我们再来了解下SurfaceFlinger的一些初始化操作:

首先SurfaceFlinger 的实例化会执行到:onFirstRef()

//SurfaceFlinger.cpp
void SurfaceFlinger::onFirstRef() {
    mEventQueue.init(this); //初始化MessageQueue , mEventQueue.init中又会创建Looper与Handler。
}

然后会执行到 SurfaceFlinger::init():

//SurfaceFlinger.cpp
void SurfaceFlinger::init() {
    Mutex::Autolock _l(mStateLock);
    //初始化 EGL,作为默认的显示
    mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglInitialize(mEGLDisplay, NULL, NULL);
    // 初始化硬件 composer 对象
    mHwc = new HWComposer(this, *static_cast<HWComposer::EventHandler *>(this));
    //获取 RenderEngine 引擎
    mRenderEngine = RenderEngine::create(mEGLDisplay, mHwc->getVisualID());
    //检索创建的 EGL 上下文
    mEGLContext = mRenderEngine->getEGLContext();
    //初始化非虚拟显示屏
    for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
        DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
        //建立已连接的显示设备
        if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
            bool isSecure = true;
            createBuiltinDisplayLocked(type);
            wp<IBinder> token = mBuiltinDisplays[i];
            sp<IGraphicBufferProducer> producer;
            sp<IGraphicBufferConsumer> consumer;
            //创建 BufferQueue 的生产者和消费者
            BufferQueue::createBufferQueue(&producer, &consumer,
                    new GraphicBufferAlloc());
            sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i, consumer);
            int32_t hwcId = allocateHwcDisplayId(type);
            //创建显示设备
            sp<DisplayDevice> hw = new DisplayDevice(this,
                    type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
                    fbs, producer,
                    mRenderEngine->getEGLConfig());
            if (i > DisplayDevice::DISPLAY_PRIMARY) {
                hw->setPowerMode(HWC_POWER_MODE_NORMAL);
            }
            mDisplays.add(token, hw);
        }
    }
    getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
    //当应用和 sf 的 vsync 偏移量一致时,则只创建一个 EventThread 线程
    if (vsyncPhaseOffsetNs != sfVsyncPhaseOffsetNs) {
        sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
                vsyncPhaseOffsetNs, true, "app");
        mEventThread = new EventThread(vsyncSrc);
        sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
                sfVsyncPhaseOffsetNs, true, "sf");
        mSFEventThread = new EventThread(sfVsyncSrc);
        mEventQueue.setEventThread(mSFEventThread);
    } else {
        //创建 DispSyncSource 对象
        sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
                vsyncPhaseOffsetNs, true, "sf-app");
        //创建线程 EventThread
        mEventThread = new EventThread(vsyncSrc);
        //设置 EventThread
        mEventQueue.setEventThread(mEventThread);
    }
    //创建 EventControl
    mEventControlThread = new EventControlThread(this);
    mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
    //当不存在 HWComposer 时,则设置软件 vsync
    if (mHwc->initCheck() != NO_ERROR) {
        mPrimaryDispSync.setPeriod(16666667);
    }
    //初始化绘图状态
    mDrawingState = mCurrentState;
    //初始化显示设备
    initializeDisplays();
    //启动开机动画
    startBootAnim();
}

该方法主要是执行一些初始化工作,包括:EGL标准下OpenGL环境的创建、创建 HWComposer、初始化非虚拟显示屏、启动 EventThread 线程、启动开机动画等等。

在这里,有几个比较重要的对象需要介绍下:

  1. EGL:OpenGL是一个操作GPU的API,它通过驱动向GPU发送相关指令,控制图形渲染管线状态机的运行状态。但OpenGL需要本地视窗系统进行交互,这就需要一个中间控制层,最好与平台无关。EGL正是这个中间控制层,它作为OpenGL ES和本地窗口的桥梁,主要作用是:其主要作用是为OpenGL指令创建 Context 、绘制目标Surface 、配置Framebuffer属性、Swap提交绘制结果等。

  2. HWComposer: 硬件组合抽象层,介于SurfaceFlinger和HAL之间,具体到代码级别就是一个类,封装对于Hwcomposer HAL和Gralloc HAL的使用。 主要作用是:一方面处理部分SurfaceFlinger委托过来的合成工作,另一方面就是产生vsync信号

  3. EventThread: 它是Surfaceflinger中的一个线程 ,主要作用:接收VSync事件通知,并分发VSync通知给系统中的每一个感兴趣的注册者。

二、SurfaceFlinger图层合成过程

2.1 什么是图层合成

图层合成就是把多个图层按既定的显示区域,展现到显示屏上。

例如Android手机的Launcher主界面图层合成如下:


adb shell dumpsys SurfaceFlinger

com.android.systemui.ImageWallpaper
com.miui.home/com.miui.home.launcher.Launcher
StatusBar
2.2 SurfaceFlinger合成消息

SurfaceFlinger合成图层依赖于Android的异步消息处理机制。

首先,它包含了一个MessageQueue对象(消息队列)用于处理各种异步消息,在onFirstRef()中对消息队列进行了初始化:

//SurfaceFlinger.cpp
SurfaceFlinger::onFirstRef()
{
    mEventQueue.init(this);
}

分析一下MessageQueue的实现:

//MessageQueue.cpp
void MessageQueue::init(const sp<SurfaceFlinger>& flinger)
{
   mFlinger = flinger;//保存MessageQueue的拥有者SurfaceFlinger
   mLooper = new Looper(true);//创建Looper对象
   mHandler = new Handler(*this);//创建Handler对象
}

调用Handler::handleMessage()处理INVALIDATE和REFRESH消息,并将其转发给SurfaceFlinger进行处理,调用onMessageReceived():

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

接下来看一下SurfaceFlinger对消息的处理:

void SurfaceFlinger::onMessageReceived(int32_t what) {
   ATRACE_CALL();
   switch (what) {
       case MessageQueue::INVALIDATE: {
           bool refreshNeeded = handleMessageTransaction();
           refreshNeeded |= handleMessageInvalidate();
           refreshNeeded |= mRepaintEverything;
           if (refreshNeeded) {
               // Signal a refresh if a transaction modified the window state,
               // a new buffer was latched, or if HWC has requested a full
               // repaint
               signalRefresh();
           }
           break;
       }
       case MessageQueue::REFRESH: {
           handleMessageRefresh();
           break;
       }
   }    
}

SurfaceFlinger处理的消息分为两种:

INVALIDATE消息:用于处理Layer或者display属性的变化以及Layer对应buffer的更新。

 1) Layer或者Display属性的更新通过调用handleMessageTransaction()处理;

 2) buffer的更新通过调用handleMessageInvalidate()处理。

REFRESH消息:表示SurfaceFlinger需要进行一次合成操作(Refresh),通过handleMessageRefresh()实现;主要有三种情况:

 1) Layer属性的变化导致window state发生变化;

 2) Layer有新的buffer到来;

 3) HWC请求进行一次repaint。

如果这三种情况之一发生,则置refreshNeeded为true,调用signalRefresh()发出MessageQueue::REFRESH消息;

当VSync信号来之前,Layer或者display属性的变化会做本地保存,只有当VSync信号到来时,SurfaceFlinger才会通过INVALIDATE和REFRESH消息来做统一的合并渲染和输出的处理工作。

2.3 handleMessageTransaction()

处理之前对屏幕和应用程序窗口的改动。因这些改动很有可能会改变图层的可见区域,进而影响脏区域的计算。

主要处理以下几个方面的transaction:

1)Layer属性的变化;
2)Layer的增加和减少;
3)Display属性的变化;
4)Display的增加和减少;
2.4 handleMessageInvalidate()

主要调用handlePageFlip()函数。这里Page Flip是指从BufferQueue中取下一个图形缓冲区内容,就好像是“翻页”一样。该函数主要是从各Layer对应的BufferQueue中拿图形缓冲区数据,并根据内容更新脏区域(注:脏区域是需要重绘的屏幕区域。)。并且把GraphicBuffer映射为OpenGL的texture 。

2.5 handleMessageRefresh()

合并和渲染输出。

void SurfaceFlinger::handleMessageRefresh() {
   ...
    preComposition(); //合成前的准备
    rebuildLayerStacks();//重建layer堆栈
    setUpHWComposer();//hwcomposer的设定
    doComposition();//正式的合成处理
    postComposition(refreshStartTime);//合成后期的处理
   ...
}
2.5.1 void SurfaceFlinger::preComposition()

合成前准备工作。首先得到当前所有layer的集合,然后对所有的Layer调用其onPreComposition()检查是否需要ExtralInvalidate,如果需要就调用一次signalLayerUpdate(),即通过EventThread安排一次vsync。

2.5.2 void SurfaceFlinger::rebuildLayerStacks()

计算可见layer及它们的可见区域。首先每个layer都有一个layerStack来区别它属于哪个Display,系统的Display可能不止一个,所以需要逐个处理Display,根据所有layers的当前状态通过SurfaceFlinger::computeVisibleRegions方法计算各个Layer在当前display上的可见区域和脏区域等。最后把需要绘制的layer添加到layersSortedByZ中。

2.5.3 void SurfaceFlinger::setUpHWComposer()

为合成搭建环境。这个HWComposer并不是真正的Hal模块,而是surfaceflinger为管理HWComposer模块而设计的一个类,路径是:frameworks/native/service/surfaceflinger/displayhardware/。依次处理各个Display,构造WorkList,合成过程既可以有Hwc模块完成,也可以通过OpengGlEs来完成,具体用哪种方式是有prepare()中的compositionType来决定的。

2.5.4 void SurfaceFlinger::doComposition()

执行合成操作。执行openGl合成 or HWC合成。

2.5.5 void SurfaceFlinger::postComposition(refreshStartTime)

将图像传递到物理屏幕。

最后借用一张流程图做最后的总结:

from Jeanboydev

参考:
https://blog.csdn.net/jxt1234and2010/article/details/46057267
https://blog.csdn.net/freekiteyu/article/details/79483406
https://blog.csdn.net/u012878643/article/details/71104467

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容