本篇针对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.即getComposerServicestatic 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进程开启后,线程池限制最大数量为4ProcessState::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 initset_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即注册GPUservicesp<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 scopeMutex::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 jitterstruct 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 statemDrawingState = 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以上源码)很多地方还不理解,所以有不正确的地方还请指正。

「Android」SurfaceFlinger分析相关推荐

  1. android surfaceflinger 老罗,「Android」SurfaceFlinger分析

    本篇针对surfaceFlinger模块进行分析,目录如下: 1.SurfaceFlinger功能 1.1.BufferQueue原理(native/libs/gui模块) 1.2   layer显示 ...

  2. android linux 优化,【「Android」UE手游研发中,如何做好Android内存优化?】|Linux|DEX|腾讯游戏|_傻大方...

    傻大方提要:[「Android」UE手游研发中,如何做好Android内存优化?]编者按在大年夜多半人的印象里,用UE引擎制造出来的游戏实际占用内存会比较高.腾讯游戏学院专家Leonn,将和大年夜家分 ...

  3. 「Android」开发小技巧合集

    「Android」开发小技巧合集 沉浸式标题栏 修改主题样式颜色 隐藏标题栏进行自主设置 状态栏设置代码 圆型图片 设置APP图标 修改APP名称 创建不同分辨率图片文件夹 更改项目名称 Button ...

  4. android+归属地+数据库,「Android」来去电显示归属地、归属地查询的小程序。

    为什么要做这个呢?这学期选了一个<移动通讯软件设计>的课程,要求做个程序当小作业吧,哎!学校开的课程各种乱,无力吐槽了 .对android 开发之前完全没有接触过,自己摸索中做的,参照了网 ...

  5. Android dumpsys SurfaceFlinger分析

    对于分析一些显示问题,我们需要使用adb shell dumpsys SurfaceFlinger命令来获取SurfaceFlinger的dump信息,因此这里来详细讲解下SurfaceFlinger ...

  6. 「Android」 APK瘦身探索

    本文来自尚妆Android团队青峰 发表于尚妆博客 APK瘦身探索 最近几周一直在研究如何为APK瘦身,折腾了很久,是时候写篇博客总结一下了,虽然已经准备了下周一要在客户端周会分享用的PPT:APK瘦 ...

  7. 「Android」 详细全面的基于vue2.0Weex接入过程(Android视角)

    本文来自尚妆Android团队路飞 发表于尚妆github博客,欢迎订阅! 一.说在前面的话 目前weex已在尚妆旗下的达人店app上线了一个常用的订单管理页面,截止目前Android上未发现问题,渲 ...

  8. android可用视频地址,「Android」一款可以获取国内各大视频网站直接播放地址的应用...

    GetVideo 是一款可以在 Android 手机上获取各大视频网站直接播放地址的应用,之后便可以配合 MX Player 播放,支持芒果tv.央视.优酷.腾讯.爱奇艺.聚力体育等网站. 开始青小蛙 ...

  9. 「Bug」问题分析 RuntimeError: CUDA error: device-side assert triggered

    最近在训练模型的时候,跑着跑着会莫名其妙的报 CUDA error 并且提示 idx_dim>=0 && idx_dim < index_size && & ...

最新文章

  1. shell 脚本执行 sql
  2. Linux的开源免费办公软件,开源免费Office办公套件(LibreOffice)
  3. 网线主管(信息学奥赛一本通-T1242)
  4. linux 上管理mysql_Linux下管理MySql
  5. 华为高级研究员谢凌曦:下一代AI将走向何方?盘古大模型探路之旅
  6. 【5.0】对象生命周期及crud操作
  7. 关于强连通图和欧拉图的一些粗浅理解
  8. 视频流(自适应算法)
  9. 通信原理包络是什么意思_为什么齿轮不能少于17个齿,少于17个齿,齿轮传动会如何?...
  10. 通孔的作用是什么linux,转载:PCB名詞解釋:通孔、盲孔、埋孔
  11. 广为流传的一个关于项目管理的通俗讲解
  12. Flutter播放音频
  13. PG数据库内核源码分析——UPDATE
  14. 我为 Redis 找到了一个新家——Redis 之父当年的困兽之斗
  15. 2019年已经过去1/4,当初的愿望都实现了吗
  16. livy(0.5) on zeppelin(0.8)报No YARN application is found with tag问题解决
  17. shell网络编程netstat
  18. Geant4在ubuntu系统的安装
  19. sping boot 配置多数据源
  20. AutoJs学习-文字转语音QQ发送

热门文章

  1. 深度学习开发任务实例(无人小车)
  2. 已知两个坐标系下的坐标,求坐标系之间的转换矩阵(一)
  3. 计算机房灭火器单具基准,灭火器的配置基准(4页)-原创力文档
  4. 【Anaconda+Pytorch+DGL】安装+配置详细过程
  5. Kafka实战宝典:Kafka的控制器controller详解
  6. pygame编写音乐播放器
  7. mysql 1243_MySQL-proxy代理导致PHP PDO::ATTR_EMULATE_PREPARES的预处理出错,MySQL报General error: 1243错误...
  8. php声明一个抽象类,如何在PHP中的非抽象类中声明抽象方法?
  9. java语言程序设计丁振凡答案下载,java语言程序设计答案丁振凡
  10. 王易见新浪SHOW开讲------余额宝真的安全吗?