surfaceflinger的使用,可以参考Android 系统源码的 frameworks\native\services\surfaceflinger\tests\resize\resize.cpp 文件,如下:
这虽然是一个c++ 的应用demo,但是android层也是这么用的,也是这么一个流程。只是android 统一用WMS 来对每一个apk做这几步。比如第5步,向buffer里面填充数据,在WMS里面来说就是draw函数,ui的绘制,最终也是向buffer里面填充数据。
目录
本文只记录关键信息,做个分析笔记。
一般来说应用在使用SurfaceFlinger服务的流程分为以下几步:
一、new SurfaceComposerClient()
创建应用进程的Client ,这个Client 是一个 SurfaceComposerClient 对象,主要用来创建一个surface:
sp<SurfaceComposerClient> client = new SurfaceComposerClient()
其UML 流程图如下:
二、createSurface
①用第一步创建的Client 获得一个surfaceControl 对象,这个surfaceControl 类是用来管理surface的:
sp<SurfaceControl> surfaceControl = client->createSurface(String8("resize"),160, 240, PIXEL_FORMAT_RGB_565, 0);
android wms 里面创建 SurfaceControl 是从调用WindowStateAnimator.createSurfaceLocked()开始的。
...
↓
windowManagerService.relayoutWindow()
↓
WindowStateAnimator.createSurfaceLocked()
↓
new SurfaceControl()
↓
android_view_SurfaceControl.nativeCreate()
↓
sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj))
↓
sp<SurfaceControl> surface = client->createSurface(...)
②第二步,得到这个surfaceControl 以后,就可以通过 surfaceControl的getSurface 方法拿到当前的一个surface。
sp<Surface> surface = surfaceControl->getSurface();
client->createSurface(...) 和surfaceControl->getSurface() 的UML图见下:
那么 wms 在获得了surfaceControl 之后又是怎么获得这个 surface 的呢?
在sp<SurfaceControl> surface = client->createSurface(...) 之后,会返回到wms 里面调用 WindowStateAnimator.createSurfaceLocked() 的地方继续向下执行,就下来的函数流程:
...
↓
SurfaceControl surfaceControl = winAnimator.createSurfaceLocked();
outSurface.copyFrom(surfaceControl)
↓
android_view_Surface.nativeCreateFromSurfaceControl(surfaceControlPtr)
↓
sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlPtr));
sp<Surface> surface(ctrl->getSurface());
return reinterpret_cast<jint>(surface.get());
通过这样一个流程就拿到底层的surface 了,并把这个surface保存在java层的 surface.java 类(outSurface )里面 mNativeObject 变量里面,最终会把outSurface 返回保存到 ViewRootImpl 类的成员变量 mSurface中,以后就可以执行draw过程了。
详细解释:
sp<Surface> surface = surfaceControl->getSurface() ;这句话其实就是在 surfaceControl 类中new 了一个surface 对象,mSurfaceData = new Surface(mGraphicBufferProducer, false) ,这个mGraphicBufferProducer 是从sp<SurfaceControl> surfaceControl = client->createSurface(...)中返回来的,createSurface ()本质是创建一个Layer 对象,这个Layer在创建的时候,就会创建一个生产者mBufferQueue对象 ,mBufferQueue = new SurfaceTextureLayer(mFlinger);其实应用层拿到surface 以后,绘制图像的过程就是在往生产者里面写入东西!所以,surface 里面的mGraphicBufferProducer 对象Layer 里面的 mBufferQueue ,他们就是同一个东西!
三、lock
当我们的应用这边获取到了surface 是不是就可以,绘图了呢?答案是否定的,此时我们虽然有了mGraphicBufferProducer 吧,但是它里面有一个BufferSlot 的结构体见 BufferQueue.h 文件,结构体里面有一个sp<GraphicBuffer> mGraphicBuffer 成员变量,还没有被分配初始化。我们需要对这个成员变量进行分配初始化,这样应用层才会有得到一个应用层的地址,绘图才会往这个地址写内容。那这个过程叫lock,分配buffer!
ANativeWindow_Buffer outBuffer;
surface->lock(&outBuffer, NULL);//分配buffer
ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
android_memset16((uint16_t*)outBuffer.bits, 0xF800, bpr*outBuffer.height);//绘图,往地址里面填入UI信息
surface->lock(&outBuffer, NULL) 这个过程的UML图:
他的内存最终是从android的HAL层的 Gralloc 模块中分配出来的。Gralloc模块,会调用芯片厂商的实现。
那么,android 里面wms ,它里面是怎么去分配buffer的呢?
当应用程序做完 测量(Measure)、布局(Layout) 等流程后,就会跑到 ViewRootImpl.drawSoftware() 软件渲染绘制UI的方法(这里只关注软件渲染ui的流程):如下/**14*/步骤就是渲染绘制的过程。
/**1*/ ApplicationThread的onTransact方法接收到SystemServer进程的SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION启动Activity的Binder信息
↓
/**2*/ ApplicationThread.scheduleLaunchActivity()
↓
/**3*/ ActivityThread.scheduleLaunchActivity() //安排启动Activity
↓
/**4*/ ActivityThread.handleLaunchActivity() //处理启动Activity
↓
/**5*/ ActivityThread.handleResumeActivity() // Activity 的Resume会使DecorView跟ViewRootImpl关联
↓
/**6*/ WindowManagerGlobal.addView() //全局保存窗口的信息
↓
/**7*/ ViewRootImpl.setView() //使DecorView和ViewRootImpl关联并绘制界面
↓
/**8*/ ViewRootImpl.requestLayout() //请求绘制ViewTree
↓
/**9*/ ViewRootImpl.scheduleTraversals() // 安排遍历
↓
/**10*/ ViewRootImpl.doTraversal()
↓
/**11*/ ViewRootImpl.performTraversals() //执行遍历 会根据情况调用relayoutWindow performMeasure performLayout performDraw 等方法 这四个方法跟绘制是紧密相关的
↓
/**12*/ ViewRootImpl.performDraw() //执行绘制
↓
/**13*/ ViewRootImpl.draw(boolean fullRedrawNeeded)//区分是否支持硬件加速来走不同的绘制流程
↓
/**14*/ViewRootImpl.drawSoftware() //这里我们就选择软件渲染的流程
↓
/**15*/Surface.lockCanvas()
↓
/**16*/android_view_Surface.nativeLockCanvas()
↓
/**17*/surface.lock(...) //native 的lock
四、unlockAndPost
当应用程序在申请的surface 上 ,做完绘画以后,就要把buffer 提交给SurfaceFlinger 进程,让其提交给Framebuffer,最终显示,使用的函数是:
surface->unlockAndPost()
其整个UML 图如下:
unlockAndPost 函数调用 queuebuffer 入队列之后,在BufferQueue这一层开始往surfaceflinger 通知消息,可以关注一下UML BufferQueue那一列, 中注释的 listener = mConsumerListener ;这个mConsumerListener 是怎么来的。
回到本文第二章节,在创建createSurface 的时候,本质是创建Layer ,每一个layer对应一个surface。在Layer被创建的时候,layer中的onFirstRef 函数会被调用,如下:
void Layer::onFirstRef() {
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
mBufferQueue = new SurfaceTextureLayer(mFlinger);
mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mBufferQueue, mTextureName);
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
mSurfaceFlingerConsumer->setFrameAvailableListener(this);
mSurfaceFlingerConsumer->setName(mName);
......
}
在onFirstRef 函数中会去初始化这个layer中的mBufferQueue成员变量,然后会初始化sp<SurfaceFlingerConsumer> mSurfaceFlingerConsumer 成员变量,SurfaceFlingerConsumer 父类是ConsumerBase ,在构造mSurfaceFlingerConsumer 的同时,会先构造
父类ConsumerBase,在父类里面就创建了 一个 Listener,并把这个Listener,通过mConsumer->consumerConnect(proxy, controlledByApp)赋值给了BufferQueue对象的mConsumerListener 变量!
ConsumerBase::ConsumerBase(const sp<IGraphicBufferConsumer>& bufferQueue, bool controlledByApp) :
mAbandoned(false),
mConsumer(bufferQueue) {
........
wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this);
sp<IConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener); //ConsumerBase 被构造的时候,构造了 ProxyConsumerListener,传递了listener
status_t err = mConsumer->consumerConnect(proxy, controlledByApp); //放入mConsumerListener
...............
}
所以,当BufferQueue对象拿到了mConsumerListener 变量,那么以后在queuebuffer过程中,把buffer入队以后,就可以通过 mConsumerListener 一层一层的通知surfaceflinger 了。
最终是调用到surfaceflinger 的 signalLayerUpdate 函数,进行通知。后面surfaceflinger是怎么处理buffer 的数据的,以后再做分析。