针对Jelly Bean版本的代码。
SurfaceFlinger是什么,这些介绍大家可以在网络上找找看,这里就直接上代码。
首先我们得了解一种常用的编程做法,生产者/消费者模型,也许都会觉得很简单,但是这里就用到了很多这些基本概念。
BufferQueue 数据都queue到这里面,前提是它是先从BufferQueue取出一个空的数据单元,称为一个buffer,实际为GraphicBuffer类型。
ConsumerBase 它是消费者端使用的接口,它实现了BufferQueue::ConsumerListener接口,也就是BufferQueue当中有buffer被queue的时候,它能被通知到(onFrameAvailable)。同理当生产者disconnect与BufferQueue的连接或者setBufferCount被调用(该方法释放掉所有buffer,让buffer都归BufferQueue所有,如果有buffer处于DEQUEUED状态,此方法返回错误),它也会被通知到(onBuffersReleased)。
BufferItemConsumer和CpuConsumer 它们都是ConsumerBase的子类,BufferItemConsumer一次可以acquire多个buffer,ConsumerBase一次只能一个,BufferItemConsumer是修改了BufferQueue的mMaxAcquiredBufferCount参数,ConsumerBase使用的默认值1。CpuBuffer可以把buffer锁起来供CPU使用,它也是调用GRALLOC的方法来完成这个功能的。
FramebufferSurface ConsumerBase的子类,会把收到的数据通过HWComposer往荧幕上贴。
SurfaceTexture ConsumerBase的子类,它可以把GraphicBuffer转换成texture image,然后交给OpenGL。
SurfaceTextureLayer是一个定制化的BufferQueue,NATIVE_WINDOW_API_MEDIA/NATIVE_WINDOW_API_CAMERA过来的请求会把BufferQueue设置为异步模式。
BufferQueue当中buffer的状态,这个很简单,但是也很重要。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
// BufferState represents the different states in which a buffer slot
// can be.
enum
BufferState {
// FREE indicates that the buffer is not currently being used and
// will not be used in the future until it gets dequeued and
// subsequently queued by the client.
// aka "owned by BufferQueue, ready to be dequeued"
FREE =
0
,
// DEQUEUED indicates that the buffer has been dequeued by the
// client, but has not yet been queued or canceled. The buffer is
// considered 'owned' by the client, and the server should not use
// it for anything.
//
// Note that when in synchronous-mode (mSynchronousMode == true),
// the buffer that's currently attached to the texture may be
// dequeued by the client. That means that the current buffer can
// be in either the DEQUEUED or QUEUED state. In asynchronous mode,
// however, the current buffer is always in the QUEUED state.
// aka "owned by producer, ready to be queued"
DEQUEUED =
1
,
// QUEUED indicates that the buffer has been queued by the client,
// and has not since been made available for the client to dequeue.
// Attaching the buffer to the texture does NOT transition the
// buffer away from the QUEUED state. However, in Synchronous mode
// the current buffer may be dequeued by the client under some
// circumstances. See the note about the current buffer in the
// documentation for DEQUEUED.
// aka "owned by BufferQueue, ready to be acquired"
QUEUED =
2
,
// aka "owned by consumer, ready to be released"
ACQUIRED =
3
};
|
BufferQueue主要方法
dequeueBuffer取一个buffer(返回slot,这个bufer是从State为FREE的当中取的)给client使用,必要时候(null/height/width/format/usage任何一点不满足都会触发)它会使用GraphicBufferAlloc::createGraphicBuffer()去分配buffer
requestBuffer根据一个指定的slot获取它的buffer的地址,这个主要用在刚刚分配buffer之后(或者是意外的发现指定slot的buffer地址为空),目前在SurfaceTextureClient(Surface)当中被使用到
queueBuffer通知BufferQueue压入了一个装满数据的buffer,QueueBufferInput是该buffer的描述数据,QueueBufferOutput是BufferQueue当前的状态(默认height/width/transformHint/slot的数量,这个slot只是当前被还回给BufferQueue)
acquireBuffer获取一个pending buffer的拥有权,这个buffer是mQueue当中,也就是状态为QUEUED的(有没有数据?)。
releaseBuffer放弃持有的指定slot的buffer
freeBuffer或者cancelBuffer都会导致这个buffer处于FREE状态
ConsumerBase的主要方法
acquireBufferLocked/releaseBufferLocked/freeBufferLocked/abandonLocked
另外这个protected的数组也很重要,子类可以直接从它里面获取buffer的信息,它实际就相当于缓存了BufferQueue的一些必要信息。
1
2
3
4
5
6
7
8
|
// mSlots stores the buffers that have been allocated by the BufferQueue
// for each buffer slot. It is initialized to null pointers, and gets
// filled in with the result of BufferQueue::acquire when the
// client dequeues a buffer from a
// slot that has not yet been used. The buffer allocated to a slot will also
// be replaced if the requested buffer usage or geometry differs from that
// of the buffer allocated to a slot.
Slot mSlots[BufferQueue::NUM_BUFFER_SLOTS];
|
SurfaceTextureClient是一个ANativeWindow,为native_window_api_*和native_window_*方法(这些都在system/core/include/system/window.h当中)做具体实现,另外它还持有SurfaceTexture。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// Initialize the ANativeWindow function pointers.
ANativeWindow::setSwapInterval = hook_setSwapInterval;
ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
ANativeWindow::cancelBuffer = hook_cancelBuffer;
ANativeWindow::queueBuffer = hook_queueBuffer;
ANativeWindow::query = hook_query;
ANativeWindow::perform = hook_perform;
ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;
ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED;
ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED;
const_cast<
int
&>(ANativeWindow::minSwapInterval) =
0
;
const_cast<
int
&>(ANativeWindow::maxSwapInterval) =
1
;
|
一些重要的命名改动
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
早期的Jelly Bean当中,比如(
4.1
/
4.2
)
4.3
================================================================================
SurfaceTextureClient和Surface(继承 被简化成了Surface(ANativeWindow)
自SurfaceTextureClient)实际就是一个
ANativeWindow
================================================================================
ISurfaceTexture IGraphicBufferProducer,
Binder IPC接口,用来在不同组件之间
传输数据使用(跨进程的),BufferQueue
实现了BnGraphicBufferProducer
================================================================================
SurfaceTexture(ConsumerBase) GLConsumer(ConsumerBase)它取
BufferQueue里面的数据,然后作为一个
texture提供给OpenGL使用
|
上面是会用到的基本知识,下面基本才直接和SurfaceFlinger相关。
箭头的方向为继承的方向
1
2
3
4
5
6
|
BpSurface ---->>>> ISurface
sp<ISurfaceTexture> ISurface::getSurfaceTexture()
BSurface ---->>>> BnSurface ---->>>> ISurface
sp<ISurfaceTexture> BSurface::getSurfaceTexture()
SurfaceTexture::getBufferQueue()
|
1
2
3
4
5
6
|
Layer ---->>>> LayerBaseClient ---->>>> LayerBase
sp<ISurface> Layer::createSurface()
new
BSurface
sp<ISurface> LayerBaseClient::getSurface()
sp<ISurface> LayerBaseClient::createSurface()
|
1
2
3
4
5
6
7
8
9
10
|
BpSurfaceComposerClient ---->>>> ISurfaceComposerClient
sp<ISurface> ISurfaceComposerClient::createSurface()
Client ---->>>> BnSurfaceComposerClient ---->>>> ISurfaceComposerClient
Client::createSurface()
SurfaceFlinger::createLayer()
createXXXLayer()
new
LayerXXX
Layer::getSurface()
Layer::createSurface()
|
1
2
3
4
|
sp<SurfaceControl> SurfaceComposerClient::createSurface()
ISurfaceComposerClient::createSurface()
new
SurfaceControl(ISurface)
// SurfaceComposerClient只是个普通的工具类,它的createSurface会去调用ISurfaceComposerClient和createSurface
|
现在来看一种情况,假设客户端要创建一个SurfaceView,这中间会发生什么样的事情。
当然你先得了解在Java层当中SurfaceView/SurfaceHolder/Surface这三者是什么关系。
1
2
3
4
5
6
|
=================================Java=====================================================
new
SurfaceView
surface =
new
Surface
// 这个是SurfaceView当中的Surface(这都是空的,不会在服务端真正的去创建一个Surface)
newSurface =
new
Surface
// 这个是新的Surface,当Surface改变/被创建/被销毁/需要重绘,
// 都会是现在系统层准备好,然后再复制来替代我们SurfaceView当
// 中的原来的Surface(通过transferFrom完成)
|
真正创建Surface的方法是系统去调用的,app不会直接去调用,但是一旦被调用之后就会进入到JNI层相应方法之中,
会用到一个SurfaceSession,书面解释是表示到Surface Flinger的一次会话,因为客户端要同服务端沟通,就存在这样一个会话的概念,这个实际就是Native层SurfaceComposerClient的一个实例。
1
2
3
4
5
6
7
8
9
10
11
12
|
=================================JNI&Native========================================
android_view_Surface.cpp nativeCreate()
android_view_SurfaceSession_getClient
SurfaceComposerClient->createSurface
ISurfaceComposerClient->createSurface
// IPC
Client->createSurface
SurfaceFlinger->createLayer
createXXXLayer()
new
LayerXXX
Layer->getSurface()
new
SurfaceControl
// SurfaceControl包含创建出来的ISurface
setSurfaceControl
// 保存到JNI Context当中
|
这样Isurface就创建好了
再来看另外一路发生了什么事情,Window/View System需要初始化整个Window,这样在SurfaceView当中一些callback(比如resize/new-surface/onWindowVisibilityChanged/setVisibility/onDetachedFromWindow)就会被调用到,这个时候最终会去调用updateWindow,然后IWindowSession.relayout之后就会有新的Surface被产生出来,然后通过Surface.transferFrom复制到SurfaceView的Surface当中。
还有一点注意的地方Java层的Surface(Surface.java)是如何转化为Native层的Surface(Surface.h|cpp,也就是SurfaceTextureClient)的,注意Surface.java持有一个名为mNativeSurface的Surface.h|cpp的指针,然后每次新创建Native层的Surface之后,就会把它保存到JNI Context当中,然后Java/Native就是通过这么来转换的。
接着我们就只看Native层Surface的管理,android_view_Surface.h|cpp当中有这么个方法android_view_Surface_getNativeWindow
而它又去调用一个内部方法getSurface,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
static
sp<Surface> getSurface(JNIEnv* env, jobject surfaceObj) {
sp<Surface> result(android_view_Surface_getSurface(env, surfaceObj));
// 如果取出来为空
if
(result == NULL) {
/*
* if this method is called from the WindowManager's process, it means
* the client is is not remote, and therefore is allowed to have
* a Surface (data), so we create it here.
* If we don't have a SurfaceControl, it means we're in a different
* process.
*/
SurfaceControl*
const
control = reinterpret_cast<SurfaceControl*>(
env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurfaceControl));
if
(control) {
result = control->getSurface();
// 创建Surface(SurfaceTextureClient)
if
(result != NULL) {
result->incStrong(surfaceObj);
env->SetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurface,
// Native关联变量,gui/Surface.h
reinterpret_cast<jint>(result.get()));
}
}
}
return
result;
}
sp<ANativeWindow> android_view_Surface_getNativeWindow(JNIEnv* env, jobject surfaceObj) {
// 这是供Native Activity使用的
return
getSurface(env, surfaceObj);
}
|
看似这就是创建Surface的地方,实则不然,这是供Native Activity使用。我们普通的Java Activity是createFromParcel。
创建的过程当中会初始化ISurface变量,这个是从SurfaceFlinger的Layer的创建的,另外也会通过ISurface->getSurfaceTexture()取得BufferQueue,这样(Surface)SurfaceTextureClient和BufferQueue也就建立起了联系,也就能通过native_window_*或者ANativeWindow往BufferQueue里压入数据。
举个Camera的例子,我们知道在HAL当中每个Stream创建的时候都会有一个camera2_stream_ops参数传进去,并且在Stream的callback当中都会调用camera2_stream_ops->enqueue_buffer,然后调用到ANativeWindow->queueBuffer,最终会调用到BufferQueue的方法,所以你看如果我们喂给Camera HAL的ANativeWindow是SurfaceFlinger当中创建的话,那么Stream的数据就会回到SurfaceFlinger当中,SurfaceFlinger对需要的Layer的数据进行merge之后就可以给FB显示出来了,这就是Camera preview的原理。
SurfaceFlinger内部比较重要的一些功能或者类分析:
我们知道在Jelly Bean当中有黄油计划,主要就是引入VSYNC, Triple Buffer这些东西,Triple Buffer在Layer.h|cpp当中有提到。
那VSYNC是什么东西,简单来说就是一个固定频率的时钟,通常由显示器硬件来提供,如果硬件没有提供,那Android这里自己会模拟一个,参见HWComposer.h|cpp当中的VSyncThread这个类,实现也是非常简洁明了,自己看看代码就能明白。其实VSYNC/Triple Buffer这些东西在PC领域已经是应用多年的老技术了,感兴趣的可以自己搜索看看。
那简单的理解来看,硬件实现就是我们有注册一个callback给硬件,当有VSYNC过来的话就会被调用,当然最终会被调用到onVSyncReceived这个方法,那软件方式就是利用时钟了,每间隔固定的时间就调用onVSyncReceived。
另外还有个和VSYNC没有关系,但是却在这里出现的一个就是onHotplugReceived,就是你的外接或者虚拟显示器被拔掉或者接上会发生的事件,这里的话拔掉会导致从硬件VSYNC切换回软件方式,接上的话又会从软件切换回硬件的方式,总之这里优先使用硬件方式。
IDisplayEventConnection是客户端用来和SurfaceFlinger做VSYNC沟通的通道,利用Binder实现,比如setVsyncRate/requestNextVsync/getDataChannel这些方法,从字面意思就比较容易理解出这几个方法的含义,set就设置VSYNC事件被通知的频率,request就是手动请求一次VSYNC事件,data channel就是获取数据传递的通道,这里是BitTube实现,它是一个利用Socket实现的跨进程通信的管道,并且你可以在它上面注册感兴趣的事件,当事件到来时候,它通知你(利用epoll实现)。
所以每个客户端可以选择自己要的VYSNC的事件的频率,然后就收听事件通知就可以了,Java层的Choreographer就是利用这个实现的。我们要指导这个IDisplayEventConnection是可以有多个的,比如View系统或者Animation系统都用到这个,比如你自己写的App如果不用系统View/Animation相关的,你也可以自己利用Choreographer来注册。
那现在SurfaceFlinger是如何管理这些事件请求或者监听通知的呢?
通过EventThread,这是一个普通的Thread,客户端每调用一次SurfaceFlinger的createDisplayEventConnection就会创建一个Connection,随后被加入到EventThreade当中的mDisplayEventConnections,并触发这个线程的threadLoop来执行(没有事件需要执行的时候,该线程是睡眠状态,因为waitForEvent方法里面有wait),最后将结果通过postEvent提交给BitTupe,这样之前有在上面注册事件监听的就会收到对应的事件。
详细的代码分析请参见(https://github.com/guohai/and-notes/tree/master/surfaceflinger-jb-4.2)中文注释/可能也有少部分是我添加的英文注释。
杂项:
另外FrameBufferNativeWindow已经不再被使用了。
我们通常说在新的支持硬件加速的设备和系统上,我们倾向于使用TextureView来替代SurfaceView,这里面又是什么原因呢?
都知道SurfaceView会单独创建一个Surface,在SurfaceFlinger当中的体现也是多创建一个Layer,然后与原有的,比如Window/Status Bar等等这些Layer合并之后再在display上画出来。
那使用TextureView就不会有这么一个过程吗?是的,因为TextureView里面利用了SurfaceTexture,SurfaceTexture的创建不会导致SurfaceFlinger中多出来一个Layer,因为它是使用硬件来做的,所以TextureView必须是支持硬件加速,并且开启的情况下才能使用,否则它什么也做不了。但是它还是会创建一个Layer,只不过这个Layer是硬件来创建,管理,那软件层面就不用花这个功来做这件事情。Native层的SurfaceTexture(ConsumerBase)它负责接收过来的数据,然后通过JNI往上传View层,软件层面的工作就结束了。
P.S. 详细信息待补充