本篇针对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{

spmComposerService;

sp<:deathrecipient>mDeathObserver;

Mutex mLock;

ComposerService();voidconnectLocked();voidcomposerServiceDied();

friendclass Singleton;public://Get a connection to the Composer Service. This will block until//a connection is established.即getComposerService

static spgetComposerService();

};

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

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

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

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

sp 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);

}returnmSurfaceData;

}

通过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/surfaceflinger2 class core3 user system4 group graphics drmrpc readproc5 onrestart restart zygote6 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驱动进行命令交互。

spps(ProcessState::self());

ps->startThreadPool();//instantiate surfaceflinger即实例化,以及设置进程优先级、事物处理策略

sp flinger = newSurfaceFlinger();

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来减少强弱引用指针计数)

spsm(defaultServiceManager());

sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);//publish GpuService即注册GPUservice

sp gpuservice = newGpuService();

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),所以首先会走到RefBase的onFirstRef方法。

voidSurfaceFlinger::onFirstRef()

{

mEventQueue.init(this);

}

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

void MessageQueue::init(const sp&flinger)

{

mFlinger=flinger;

mLooper= new Looper(true);

mHandler= new Handler(*this);

}

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

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

/*MessageQueue.cpp*/

voidMessageQueue::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中的代码如下:

voidSurfaceFlinger::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 vsyncSrc = new DispSyncSource(&mPrimaryDispSync,

vsyncPhaseOffsetNs,true, "app");

mEventThread= new EventThread(vsyncSrc, *this);

sp 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<: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启动成功,开始工作。代码如下:

voidSurfaceFlinger::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构造函数,初始化一些成员变量

>>> (强指针

)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 老罗,「Android」SurfaceFlinger分析相关推荐

  1. 专访罗升阳:老罗的Android之旅

    CSDN首页 > 业界 专访罗升阳:老罗的Android之旅 发表于2014-08-15 14:13| 10091次阅读| 来源CSDN| 0 条评论| 作者钱曙光 社区问答访谈罗升阳Andro ...

  2. 【转载】专访罗升阳:老罗的Android之旅

    CSDN:你用两年的时间炼就了深厚的Android内功修养,请问期间的学习之路是怎样的?有什么学习的心得和体会可分享? 罗升阳:那两年基本是把所有的业余时间都花在了学习Android上,包括工作日的下 ...

  3. 老罗的Android系统分析(三横三纵)

    经过两年的时间,终于完成对 Android系统的研究了.Android是一个博大精深的系统,老罗不敢说自己精通了(事实上最讨厌的就是说自己精通神马神马的了,或者说企业说要招聘精通神马神马的人才),但是 ...

  4. 专访罗升阳:老罗的Android之旅(转载)

    本文转载地址:专访罗升阳:老罗的Android之旅 [编者按]我们常说的智能手机实际上就是手机上加了一个操作系统,那么大部分人都会跟我一样不禁发问,这个操作系统和我们接触更多的电脑上的操作系统一样吗. ...

  5. 《老罗的Android之旅》导读PPT

    虽然好几个月没更新博客了,但是老罗一直有在准备可以分享的东西的.除了早前在微博分享Android4.2相关技术之外,这次还特意准备了13个PPT,总结之前所研究过的东西.内容从Android组件设计思 ...

  6. 《老罗的Android之旅》专栏目录

    Android学习启动篇 在Ubuntu上下载.编译和安装Android最新源代码 在Ubuntu上下载.编译和安装Android最新内核源代码(Linux Kernel) 如何单独编译Android ...

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

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

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

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

  9. 【视频教程】老罗分享Android源代码下载和编译及如何分析源代码

    小编语:老罗(罗升阳)的Android之旅,在国内是让不少人收益,也给了我非常大的启示,老罗最近自己折腾了一个网站叫<进击的程序员>,域名:http://0xcc0xcd.com/,继续他 ...

最新文章

  1. 4层板到12层板叠层经典设计方案
  2. 女神推荐, 卡片,广告图 ,点击查看更多
  3. 在LinearLayout中嵌套RelativeLayout来设置Button的位置(xml文件)
  4. android 自定义天气特效,《Android自定义控件》WindMillView,仿华为天气风车效果
  5. linux 系统将某目录下的可执行文件添加环境变量,jenkins创建shell长链接却找不到
  6. Java泛型,枚举,注解
  7. mysql数据库安装在unix_Linux下的数据库二:在Linux/Unix平台安装MySQL
  8. [leetcode] Reverse Integer 反转一个整数
  9. php sqlite创建表,php – 使用SQLite创建列表树
  10. Redis 网络编程
  11. 问题:html控件中sleect的Option()的用法
  12. chrome浏览器再次打开黑屏一段时间
  13. matlab程序 直线插补,用Matlab实现直线插补计算程序讲解学习
  14. JDK、J2EE、J2SE、J2ME的区别(转-2021-04-30)
  15. 手机版q群管机器人_手机QQ机器人怎么用,QQ机器人手机版怎么设置
  16. vs2015水晶报表(Crystal Reports)连接Oracle11g
  17. WDF pci驱动开发的若干总结
  18. 国外android大神博客,Android手机浏览器(国外篇)横向对比评测
  19. Gartner:2017年存储技术成熟度曲线
  20. 电视不正常Android镜像投屏,爱奇艺乐播投屏

热门文章

  1. 线段树的数组大小下限及证明
  2. 点击延迟_300ms 延迟是什么,如何解决
  3. 2020-09-16 如何在matlab figure中对latex符号进行大写操作
  4. 无障碍开发(二)之ARIA role属性
  5. 实现canvas连线
  6. Python3学习笔记2:简易Web爬虫
  7. mint ui datetimepicker 手机端jquery datetimepicker 总结应用
  8. Linux文件锁flock
  9. Solaris 10绝非儿戏
  10. 4G网络在物联网应用中的重要性