「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功能:
1.1、BufferQueue原理(和SF交互)
比如应用通过windowsmanager分配一个surface,需要分配(dequeueBuffer)显示空间在上面进行绘图,在图形绘制完成后需要推送(queueBuffer)到surfaceflinger进行合成显示。
surfaceflinger作为消费者,通过acquireBuffer()得到一个要合成的图形,在合成完毕后再releaseBuffer()将图形释放。
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 == ) {
// This surface is always consumed by SurfaceFlinger, so the
// producerControlledByApp value doesn't matter; using false.
mSurfaceData = new Surface(mGraphicBufferProducer, false);
}
return mSurfaceData;
}
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文件,内容如下:
service surfaceflinger /system/bin/surfaceflinger
class core
user system
group graphics drmrpc readproc
onrestart restart zygote
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(); // 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, , PRIORITY_URGENT_DISPLAY); set_sched_policy(, 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(, 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 = {};
param.sched_priority = ;
if (sched_setscheduler(, SCHED_FIFO, ¶m) != ) {
ALOGE("Couldn't set SCHED_FIFO");
} // run surface flinger in this thread即运行当前线程
flinger->run(); return ;
}
在执行main函数的时候,执行经过了以下过程:
(1)创建SurfaceFlinger对象,在其构造函数中,主要是一些成员变量的初始化工作。在SurfaceFlinger.cpp中的构造函数代码如下:
SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(),
mTransactionFlags(),
mTransactionPending(false),
mAnimTransactionPending(false),
mLayersRemoved(false),
mRepaintEverything(),
mRenderEngine(NULL),
mBootTime(systemTime()),
mBuiltinDisplays(),
mVisibleRegionsDirty(false),
mGeometryInvalid(false),
mAnimCompositionPending(false),
mDebugRegion(),
mDebugDDMS(),
mDebugDisableHWC(),
mDebugDisableTransformHint(),
mDebugInSwapBuffers(),
mLastSwapBufferTime(),
mDebugInTransaction(),
mLastTransactionTime(),
mBootFinished(false),
mForceFullDamage(false),
mPrimaryDispSync("PrimaryDispSync"),
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false),
mHasColorMatrix(false),
mHasPoweredOff(false),
mFrameBuckets(),
mTotalTime(),
mLastSwapTime()
{......}
(2) 因为这里的SurfaceFlinger对象是一个StrongPointer(强指针,见老罗博客https://blog.csdn.net/luoshengyang/article/details/6786239),所以首先会走到RefBase的onFirstRef方法。
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(-); }
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 = {};
param.sched_priority = ;
if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != ) {
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(-);
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分析的更多相关文章
- 「Android」 Surface分析
本篇针对Surface模块进行分析,从Java层的Activity创建开始,到ViewRoot.WindowsManagerService,再到JNI层和Native层. 首先推荐一个Android源 ...
- 「Android」消息驱动Looper和Handler类分析
Android系统中的消息驱动工作原理: 1.有一个消息队列,可以往这个消息队列中投递消息; 2.有一个消息循环,不断的从消息队列中取得消息,然后处理. 工作流程: 1.事件源将待处理的消息加入到消息 ...
- 「Android」 基于Binder通信的C/S架构体系认知
C/S架构(Client/Server,即客户机/服务器模式)分为客户机和服务器两层:第一层是在客户机系统上结合了表示与业务逻辑,第二层是通过网络结合了数据库服务器.简单的说就是第一层是用户表示层,第 ...
- 「Android」adb调试源码(针对dumpsys SurfceFlinger、trace.txt获取)
首先对ADB作简单的阐述,接下来对adb shell dumpsys SurfaceFlinger服务的dump信息的查看.以及ANR问题如何获取trace文件并简单分析. -×*********** ...
- 「Android」GreenDao
译文 版本:greenDAO 3.2.2 官网:http://greenrobot.org/greendao/ GitHub:https://github.com/greenrobot/greenDA ...
- 「Android」系统架构概述
目录: 1.Android系统架构 2.Android类库 3.四大组件 --------------------------------------------------------------- ...
- 「Android」单例的五种写法
单例 发现博客园可以很好的设置自己的博客文章的展示,很开心,然后特此发一篇 其实这几种写法大家应该都会的,就权当拿来记录一下吧,以后复习巩固也比较方便. 这篇文章中的代码,来自一篇视频(我想找视频贴上 ...
- LOJ 3184: 「CEOI2018」斐波那契表示法
题目传送门:LOJ #3184. 题意简述: 题目说得很清楚了. 题解: 首先需要了解「斐波那契数系」为何物. 按照题目中定义的斐波那契数列 \(F_n\),可以证明,每个非负整数 \(n\) 都能够 ...
- Android逆向之旅---静态方式分析破解视频编辑应用「Vue」水印问题
一.故事背景 现在很多人都喜欢玩文艺,特别是我身边的UI们,拍照一分钟修图半小时.就是为了能够在朋友圈显得逼格高,不过的确是挺好看的,修图的软件太多了就不多说了,而且一般都没有水印啥的.相比较短视频有 ...
随机推荐
- js对象之XMLHttpReques对象学习
背景:业务需求是,一个前端(手机和浏览器)HTML页面中有图片,按钮......,需要统计用户点击图片或者按钮的次数. 前端实现:通过一个js来统计HTML页面中所有的图片和按钮对象,并给每个对象赋予 ...
- Lock wait timeout exceeded
MySQL事务锁问题-Lock wait timeout exceeded问题: 一次ios在请求接口响应时间超长,耗时几十秒才返回错误提示,后台日志中出现Lock wait timeout exce ...
- 使用SAX解析xml文档
1.首先,在main方法中解析xml文档,具体代码如下: import org.w3c.dom.*; import javax.xml.parsers.DocumentBuilder; import ...
- mongoose的基本操作方法
mongoose 1. const mongoose = require("mongoose");导入mongoose模块 2. //注意url地址最后面的地址是数据库的名称 ...
- JavaScript逗号操作符
今天在CSDN看到一篇文章http://www.csdn.net/article/2014-01-06/2818025-Useful-JavaScript-Tips-Best-Practices?re ...
- java提高(9)---HashMap解析
HashMap解析(一) 平时一直再用hashmap并没有稍微深入的去了解它,自己花点时间想往里面在深入一点,发现它比arraylist难理解很多. 数据结构中有数组和链表来实现对数据的存储,但这两者 ...
- java提高(8)---ArrayList源码
ArrayList源码 一.定义 public class ArrayList<E> extends AbstractList<E> implements List<E& ...
- 利用 ELK 搭建 Docker 容器化应用日志中心
利用 ELK 搭建 Docker 容器化应用日志中心 概述 应用一旦容器化以后,需要考虑的就是如何采集位于 Docker 容器中的应用程序的打印日志供运维分析.典型的比如SpringBoot应用的日志 ...
- Linux编程 16 文件权限(组管理 groupadd, groupmod,文件权限介绍)
一.用户组 前面章节知道用户账户在控制单个用户安全性方面很好,但涉及到共享资源或把用户类型分组时,组概念就出来了. 组权限允许多个用户对系统中的对象(比如文件,目录,设备等)共享一组共用的权限. 在c ...
- JAVA UUID 生成唯一标识
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket Reprint it anywhere u want 需求 项目在设计表的时候,要处理并发多的一些数据 ...