Fork me on GitHub

「Android」SurfaceFlinger分析

本篇针对surfaceFlinger模块进行分析,目录如下:

1、SurfaceFlinger功能

  1.1、BufferQueue原理(native/libs/gui模块)

  1.2   layer显示内存分配(native/libs/ui模块)

  1.3、surfaceFlinger处理(native/.../surfaceFlinger模块

2、工程代码解析:

  2.1、surfaceFlinger启动过程

  2.2、surfaceFlinger事务处理 

3、总结(处理流程、交互模块)

***********************************************************×*********************************×*******

 

1、SurfaceFlinger功能:

surfaceflinger作用是接受多个来源的图形显示数据,将他们合成,然后发送到显示设备。
比如打开应用,常见的有三层显示,顶部的statusbar底部或者侧面的导航栏以及应用的界面,每个层是单独更新和渲染,这些界面都是有surfaceflinger合成一个刷新到硬件显示。
在显示过程中使用到了bufferqueue,surfaceflinger作为consumer方,比如windowmanager管理的surface作为生产方产生页面,交由surfaceflinger进行合成。

1.1、BufferQueue原理(和SF交互)

bufferqueue分为生产者和消费者
比如应用通过windowsmanager分配一个surface,需要分配(dequeueBuffer)显示空间在上面进行绘图,在图形绘制完成后需要推送(queueBuffer)到surfaceflinger进行合成显示。
surfaceflinger作为消费者,通过acquireBuffer()得到一个要合成的图形,在合成完毕后再releaseBuffer()将图形释放。
(1)在bufferQueuei所在目录下 ComposerService 为单例模式负责与surfaceflinger建立binder连接,在native/libs/gui库
代码如下:
class ComposerService : public Singleton<ComposerService>
{
    sp<ISurfaceComposer> mComposerService;
    sp<IBinder::DeathRecipient> mDeathObserver;
    Mutex mLock;

    ComposerService();
    void connectLocked();
    void composerServiceDied();
    friend class Singleton<ComposerService>;
public:

    // Get a connection to the Composer Service.  This will block until
    // a connection is established.即getComposerService
    static sp<ISurfaceComposer> getComposerService();
};

(2)ComposerService 为单例模式负责与surfaceflinger建立binder连接;

(3)SurfaceComposerClient则在于surfaceflinger建立连接后(即getComposerService)建立与Client的连接,

  通过client调用createSurface,然后返回SurfaceControl;

(4)SurfaceControl负责这个显示层的控制。

sp<Surface> SurfaceControl::getSurface() const
{
    Mutex::Autolock _l(mLock);
    if (mSurfaceData == 0) {
        // This surface is always consumed by SurfaceFlinger, so the
        // producerControlledByApp value doesn't matter; using false.
        mSurfaceData = new Surface(mGraphicBufferProducer, false);
    }
    return mSurfaceData;
}
通过SurfaceControl::getSurface(),得到的真正的显示层,这样之后可以通过Lock和unlock将surface空间分配绘图,再返回给surfaceflinger。

1.2 layer显示内存分配

(1)surface创建后得到 mGraphicBufferProducer,new GraphicBuffer分配一个GraphicBuffer:

int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {.....}

(2) 在graphicbuffer.cpp中分配一个共享内存,在native/libs/ui模块:

GraphicBuffer::GraphicBuffer(...){...}
status_t GraphicBuffer::initWithSize(...){...}

(3)GraphicBufferAllocator::get() 使用gralloc进行内存分配,分配完成后,得到bufferIdx 将他发给client端也就是surface端

(4)返回虚拟地址给上层

 

1.3、surfaceFlinger处理

 上面创建一个surface后,surfaceflinger对应的是一个layer,当上层layer调用刷新后,onFrameAvailable被调用,通知surfaceflinger有layer更新

void BufferLayer::onFrameAvailable(const BufferItem& item) {
    mFlinger->signalLayerUpdate();
}

 

 

2、工程代码解析:

2.1、surfaceFlinger启动过程:

(代码取自其他博客提供下载的源码https://blog.csdn.net/ztguang/article/details/64905058,Android7.0以上)

 1、surfaceFlinger代码仓位置:/frameworks/native/services/surfaceflingers

    surfaceFlinger启动进程的脚本是surfceFlinger.rc文件,内容如下:

1 service surfaceflinger /system/bin/surfaceflinger
2     class core
3     user system
4     group graphics drmrpc readproc
5     onrestart restart zygote
6     writepid /dev/stune/foreground/tasks

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

  注:在.bp脚本中会初始化该脚本,之后执行main_surfaceflinger.cpp文件 (rc文件有3个socket,用于跨进程通信)

2、创建进程后执行main函数,main函数在frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp,main函数主要代码如下:

int main(int, char**) {
   //忽略了SIGPIPE信号,因为在SurfaceFlinger的Client-Server模型中,或者说IPC机制中,很可能会触发SIGPIPE信号,而这个信号的默认动作是终止进程
  ////当客户端/服务端的socket关闭时,防止进程退出 signal(SIGPIPE, SIG_IGN);
// When SF is launched in its own process, limit the number of // binder threads to 4.即SF进程开启后,线程池限制最大数量为4 ProcessState::self()->setThreadPoolMaxThreadCount(4); // start the thread pool即启动线程池
  //
大多数程序都是需要IPC的,这里也需要,但是使用Binder机制是很繁琐的,所以Android为程序进程使用Binder机制封装了两个实现类:ProcessState、IPCThreadState
  //其中ProcessState负责打开Binder驱动,进行mmap等准备工作;IPCThreadState负责具体线程跟Binder驱动进行命令交互。
    sp<processstate> ps(ProcessState::self());
    ps->startThreadPool();
 
    // instantiate surfaceflinger即实例化,以及设置进程优先级、事物处理策略
    sp<surfaceflinger> flinger = new SurfaceFlinger();
 
    setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
 
    set_sched_policy(0, SP_FOREGROUND);
 
#ifdef ENABLE_CPUSETS
    // Put most SurfaceFlinger threads in the system-background cpuset
    // Keeps us from unnecessarily using big cores
    // Do this after the binder thread pool init
    set_cpuset_policy(0, SP_SYSTEM);
#endif
 
    // initialize before clients can connect即初始化
    flinger->init();
 
    // publish surface flinger即发布SF,注册到ServiceManager,sp是strongponiter强指针(sp对象的析构函数调用RefBase的decStrong来减少强弱引用指针计数)
    sp<iservicemanager> sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);
 
    // publish GpuService即注册GPUservice
    sp<gpuservice> gpuservice = new GpuService();
    sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
 
    struct sched_param param = {0};
    param.sched_priority = 2;
    if (sched_setscheduler(0, SCHED_FIFO, ¶m) != 0) {
        ALOGE("Couldn't set SCHED_FIFO");
    }
 
    // run surface flinger in this thread即运行当前线程
    flinger->run();
 
    return 0;
}

在执行main函数的时候,执行经过了以下过程: 

(1)创建SurfaceFlinger对象,在其构造函数中,主要是一些成员变量的初始化工作。在SurfaceFlinger.cpp中的构造函数代码如下:

SurfaceFlinger::SurfaceFlinger()
    :   BnSurfaceComposer(),
        mTransactionFlags(0),
        mTransactionPending(false),
        mAnimTransactionPending(false),
        mLayersRemoved(false),
        mRepaintEverything(0),
        mRenderEngine(NULL),
        mBootTime(systemTime()),
        mBuiltinDisplays(),
        mVisibleRegionsDirty(false),
        mGeometryInvalid(false),
        mAnimCompositionPending(false),
        mDebugRegion(0),
        mDebugDDMS(0),
        mDebugDisableHWC(0),
        mDebugDisableTransformHint(0),
        mDebugInSwapBuffers(0),
        mLastSwapBufferTime(0),
        mDebugInTransaction(0),
        mLastTransactionTime(0),
        mBootFinished(false),
        mForceFullDamage(false),
        mPrimaryDispSync("PrimaryDispSync"),
        mPrimaryHWVsyncEnabled(false),
        mHWVsyncAvailable(false),
        mHasColorMatrix(false),
        mHasPoweredOff(false),
        mFrameBuckets(),
        mTotalTime(0),
        mLastSwapTime(0)
{......}

 

(2) 因为这里的SurfaceFlinger对象是一个StrongPointer(强指针,见老罗博客https://blog.csdn.net/luoshengyang/article/details/6786239),所以首先会走到RefBaseonFirstRef方法。

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

       查看surfaceFlinger.h,发现mEventQueue是MessqgeQueue创建的对象。所以初始化会创建消息队列需要的Handler、Looper。在相同目录下的MessageQueue.cpp文件中:

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

  此处MessageQueue不是常见的消息队列,在surfaceFlinger目录单独编写,mEventQueue更像是消息循环机制的管理者,其中包含了一个looper,一个handler。

  looper中的mMessageEnvelopes这个容器才是真正存储消息的地方:

/* MessageQueue.cpp */

void MessageQueue::waitMessage() {

         int32_tret = mLooper->pollOnce(-1);

}

 

  handler也不是常见的那个handler,而是Messagequeue中自定义的一个事件处理器,是专门为surfaceflinger设计的,handler收到消息,进一步回调surfaceflinger中的onMessageReceived。

void MessageQueue::Handler::handleMessage(constMessage& message) {

         switch(message.what) {

                   caseINVALIDATE:

                            mQueue.mFlinger->onMessageReceived(message.what);

}        } 

(3)之后执行surfaceFlinger::init,方法主要实现的功能

  • 初始化EGL
  • 创建HWComposer
  • 初始化非虚拟显示屏
  • 启动EventThreada线程
  • 启动开机动画

在SurfaceFlinger.cpp中的代码如下:

void SurfaceFlinger::init() {
    ALOGI(  "SurfaceFlinger's main thread ready to run. "
            "Initializing graphics H/W...");  //开始SF线程的准备工作,初始化graphics H/W

    { // Autolock scope
        Mutex::Autolock _l(mStateLock);

        // initialize EGL for the default display即初始化EGL,作为默认显示(EGL见https://blog.csdn.net/ieearth/article/details/71180457)
        mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
        eglInitialize(mEGLDisplay, NULL, NULL);

        // start the EventThread开启事件线程
        sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
                vsyncPhaseOffsetNs, true, "app");
        mEventThread = new EventThread(vsyncSrc, *this);
        sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
                sfVsyncPhaseOffsetNs, true, "sf");
        mSFEventThread = new EventThread(sfVsyncSrc, *this);
        mEventQueue.setEventThread(mSFEventThread);

        // set SFEventThread to SCHED_FIFO to minimize jitter
        struct sched_param param = {0};
        param.sched_priority = 2;
        if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) {
            ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
        }

        // Get a RenderEngine for the given display / config (can't fail)
        mRenderEngine = RenderEngine::create(mEGLDisplay,
                HAL_PIXEL_FORMAT_RGBA_8888);
    }

    // Drop the state lock while we initialize the hardware composer. We drop
    // the lock because on creation, it will call back into SurfaceFlinger to
    // initialize the primary display.即初始化硬件composer对象,和显示设备交互,硬件显示设备
    mHwc = new HWComposer(this);
    mHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this));

    Mutex::Autolock _l(mStateLock);

    // retrieve the EGL context that was selected/created即检索创建的EGL上下文
    mEGLContext = mRenderEngine->getEGLContext();

    LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
            "couldn't create EGLContext");

    // make the GLContext current so that we can create textures when creating
    // Layers (which may happens before we render something)即显示设备
    getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);

    mEventControlThread = new EventControlThread(this);
    mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);//创建EventControl

    // initialize our drawing state
    mDrawingState = mCurrentState;

    // set initial conditions (e.g. unblank default device)即初始化显示装备
    initializeDisplays();

    mRenderEngine->primeCache();

    // start boot animation即启动开机动画
    startBootAnim();

    ALOGV("Done initializing");
}

(4)Android系统中有一个ServiceManager,专门用来管理所有的服务,而SurfaceFlinger不是由ServiceManager启动的,因此需要向ServiceManager注册SurfaceFlinger,同时还注册了GpuService。(在main函数里面注册)

(5)执行SF的run方法,SurfaceFlinger::run,进入消息循环,SurfaceFlinger启动成功,开始工作。代码如下:

void SurfaceFlinger::run() {
    do {
        waitForEvent();
    } while (true);
}

(分析参考博客https://blog.csdn.net/u012439416/article/details/79733178)

waitForEvent方法如下:

mEventQueue.waitMessage();

MessageQueue的waitMessage方法也是一个do – while循环,里面逻辑如下:

>阻塞消息

IPCThreadState::self()->flushCommands();
int32_t ret = mLooper->pollOnce(-1);

flushCommands方法主要是对binder驱动进行交互, 清理binder

pollOnce是消息机制,主要调用了epoll_wait函数,会阻塞,阻塞完了会分发消息队列中的消息。这里的消息只有自己在Handler中发的消息,还有在setEventThread中自己添加的消息。
>处理不同消息

 

2.2、工作流程

  在执行SF的run方法时,SurfaceFlinger::run,进入MessageQueue.cpp中的waitForEvent方法:

 

当Surface绘制完成后会发出一个Invalidate的消息给Surfaceflinger的等待线程,当waitForEvent接收到消息后就会交给onMessageReceivered去处理,处理过程中会依次调用handleMessageTransaction、handleMessageInvalidate、handleMessageRefresh接口。
 (1)调用handleMessageTransaction时,会调用:

    > 有事务处理请求时,调用handleTransaction进行处理(getTransactionFlags)  

      > 调用handleTransactionLocked

      > commitTransactionao提交事务

    该函数主要处理之前对屏幕和应用程序窗口的改动。窗口状态的改变只能在一个Transaction中进行。因为窗口状态的改变可能造成本窗口和其他窗口的可见区域变化,所以就必须重新来计算窗口的可见区域。在这个处理子过程中Android会根据标志位来对所有layer进行遍历,一旦发现哪个窗口的状态发生了变化就设置标志位以在将来重新计算这个窗口的可见区域。

 (2)调用handleMessageInvalidate时,会调用handlePageFlip

    > handlePageFlip绘制(Layer从FrontBuffer中取得新数据,并生成一张OpenGL中的纹理。现在Layer准备好了数据,下一步开始进行绘制)

    该函数主要调用handlePageFlip()函数,该函数主要是从各Layer对应的BufferQueue中拿图形缓冲区数据,并根据内容更新脏区域。

   (3)handleMessageRefresh——进行合并和渲染输出:

   (4)合并渲染完成后,该线程继续等待下一个invalidate消息。

 

 

 

4、总结(处理流程、交互模块)

4.1、处理流程

  首先SF的启动过程:> 启动进程脚本.rc

            > main_sf.cpp的main()函数

             >> 启动线程池,设置线程最大数量

             >> 实例化(创建对象)SF.cpp

               >>> SF:SF构造函数,初始化一些成员变量

               >>> (强指针<p>)SF::onFirstRef执行到MessageQueue.cpp,执行init()创建Handler、Looper

             >> 设置进程优先级 

             >> 执行sf.init()初始化方法 

               >>> 初始化 graphics H/W ...,

               >>> 创建对象显示设备HWComposer.cpp

               >>> 创建event线程

               >>> 初始化显示设备

             >> 注册ServiceManager、GPUService

             >> 运行SF.run()方法  (详细处理合成图像)

 

 

  SF的工作流程分析(实现图像混合):

           > 在run方法中waitForEvent等待事件(MessagQueu.cpp),收到重绘消息后,将退出等待,交给onMessageReceivered去处理

           > handleMessageTransaction处理事务

              >> 有事务处理请求时,调用handleTransaction进行处理(getTransactionFlags)

             >> 调用handleTransactionLocked

             >> commitTransactionao提交事务

           > handleMessageInvalidateia调用handlePageFlip绘制

           > handleMessageRefresh合并和渲染

           > 完成后,线程继续等待下一个invalidate消息

 

          (以下是深入理解Android的讲解,源码为2.2

           > 处理事务

                >> 有事务处理请求时,调用handleTransaction进行处理(getTransactionFlags)

             >> 调用handleTransactionLocked

             >> commitTransactionao提交事务

             > handlePageFlip绘制(Layer从FrontBuffer中取得新数据,并生成一张OpenGL中的纹理。现在Layer准备好了数据,下一步开始进行绘制)

             > handleRepaint对每一层进行重绘(显示层的onDraw函数,使用OpenGL)

             > 绘制完图后,unlockClient释放之前占着FrontBuffer的索引,调用各个显示层的finishPageFlip函数

             > postFrameBuffer调用DisplayHardware.cpp的flip函数,flipg调用eglSwapBuffers函数,以完成FrameBuffer的apgeFlip操作,之后混合后的图像就会传递到屏幕中显示

 

 

  交互模块:

    应用通过windowsmanager分配一个surface,需要分配显示空间在上面进行绘图,在图形绘制完成后需要推送到surfaceflinger进行合成显示。
   surfaceflinger作为消费者,得到一个要合成的图形,在合成完毕后再将图形释放。

    大概流程:

    ->bufferqueue.cpp(../native/libs/gui库

    -> composerService(单例模式)与SF建立bind连接

    -> SurfaceComposerClinet.cpp调用createaSurfce创建surface,返回surfaceControl

    -> 创建surface后在graphicBuffer.cpp(../native/libs/ui库)分配共享内存

    -> 创建surface后,SF也对应一个layer,当上层layer调用刷新后,onFrameAvailable被调用,通知SF有layer更新 

 

  !!!初次接触,翻阅《深入理解Android》(2.2源码)以及其他的博客(Android6.0以上源码)很多地方还不理解,所以有不正确的地方还请指正。

posted @ 2018-10-18 14:11  sunwengang  阅读(7981)  评论(0编辑  收藏  举报