SF中的工作线程就是来做图像混合的,比起AudioFlinger来,它相当简单,下面是它的代码:
**SurfaceFlinger.cpp**
~~~
bool SurfaceFlinger::threadLoop()
{
waitForEvent();//① 等待什么事件呢?
if (UNLIKELY(mConsoleSignals)) {
handleConsoleEvents();
}
if(LIKELY(mTransactionCount == 0)) {
const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
uint32_t transactionFlags = getTransactionFlags(mask);
if(LIKELY(transactionFlags)) {
//Transaction(事务)处理,放到本节最后来讨论
handleTransaction(transactionFlags);
}
}
//②处理PageFlipping工作
handlePageFlip();
constDisplayHardware& hw(graphicPlane(0).displayHardware());
if (LIKELY(hw.canDraw() && !isFrozen())) {
//③处理重绘
handleRepaint();
hw.compositionComplete();
//④投递BackBuffer
unlockClients();
postFramebuffer();
} else{
unlockClients();
usleep(16667);
}
returntrue;
}
~~~
ThreadLoop一共有四个关键点,这里,分析除Transaction外的三个关键点。
1. waitForEvent
SF工作线程一上来就等待事件,它会是什么事件呢?来看代码:
**SurfaceFlinger.cpp**
~~~
void SurfaceFlinger::waitForEvent()
{
while(true) {
nsecs_t timeout = -1;
const nsecs_t freezeDisplayTimeout = ms2ns(5000);
......
MessageList::value_type msg = mEventQueue.waitMessage(timeout);
......//还有一些和冻屏相关的内容
if(msg != 0) {
switch (msg->what) {
//千辛万苦就等这一个重绘消息
case MessageQueue::INVALIDATE:
return;
}
}
}
}
~~~
SF收到重绘消息后,将退出等待。那么,是谁发送的这个重绘消息呢?还记得在unlockCanvasAndPost函数中调用的signal吗?它在SF端的实现代码如下:
**SurfaceFlinger**
~~~
void SurfaceFlinger::signal() const {
const_cast<SurfaceFlinger*>(this)->signalEvent();
}
void SurfaceFlinger::signalEvent() {
mEventQueue.invalidate(); //往消息队列中加入INVALIDATE消息
}
~~~
2. 分析handlePageFlip
SF工作线程从waitForEvent中返回后,下一步要做的就是处理事务和handlePageFlip了。先看handlePageFlip,从名字上可知,它和PageFlipping工作有关。
* * * * *
**注意**:事务处理将在8.5.3节中介绍。
* * * * *
代码如下所示:
**SurfaceFlinger.cpp**
~~~
void SurfaceFlinger::handlePageFlip()
{
bool visibleRegions = mVisibleRegionsDirty;
/*
还记得前面所说的mCurrentState吗?它保存了所有显示层的信息,而绘制的时候使用的
mDrawingState则保存了当前需要显示的显示层信息。
*/
LayerVector& currentLayers =
const_cast<LayerVector&>(mDrawingState.layersSortedByZ);
//①调用lockPageFlip
visibleRegions |= lockPageFlip(currentLayers);
const DisplayHardware& hw =graphicPlane(0).displayHardware();
//取得屏幕的区域
const Region screenRegion(hw.bounds());
if (visibleRegions) {
Region opaqueRegion;
computeVisibleRegions(currentLayers, mDirtyRegion,opaqueRegion);
mWormholeRegion = screenRegion.subtract(opaqueRegion);
mVisibleRegionsDirty = false;
}
//② 调用unlockPageFlip
unlockPageFlip(currentLayers);
mDirtyRegion.andSelf(screenRegion);
}
~~~
hanldePageFlip调用了两个看起来是一对的函数:lockPageFlip和unlockPageFlip。这两个函数会干些什么呢?
(1)lockPageFlip的分析
先看lockPageFlip函数,代码如下所示:
**SurfaceFlinger.cpp**
~~~
bool SurfaceFlinger::lockPageFlip(constLayerVector& currentLayers)
{
boolrecomputeVisibleRegions = false;
size_tcount = currentLayers.size();
sp<LayerBase> const* layers = currentLayers.array();
for(size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer = layers[i];
//调用每个显示层的lockPageFlip
layer->lockPageFlip(recomputeVisibleRegions);
}
returnrecomputeVisibleRegions;
}
~~~
假设当前的显示层是Layer类型,那么得转到Layer类去看它的lockPageFlip函数,代码如下所示:
**Layer.cpp**
~~~
void Layer::lockPageFlip(bool&recomputeVisibleRegions)
{
//lcblk是SharedBufferServer类型,调用retireAndLock函数将返回FrontBuffer的
//索引号
ssize_tbuf = lcblk->retireAndLock();
......
mFrontBufferIndex = buf;
//得到FrontBuffer对应的GraphicBuffer
sp<GraphicBuffer> newFrontBuffer(getBuffer(buf));
if (newFrontBuffer != NULL) {
//取出脏区域
const Region dirty(lcblk->getDirtyRegion(buf));
//和GraphicBuffer所表示的区域进行裁剪,得到一个脏区域
mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() );
const Layer::State& front(drawingState());
if(newFrontBuffer->getWidth() ==front.requested_w &&
newFrontBuffer->getHeight() ==front.requested_h)
{
if ((front.w != front.requested_w) ||
(front.h != front.requested_h))
{
...... //需要重新计算可见区域
recomputeVisibleRegions = true;
}
mFreezeLock.clear();
}
} else{
mPostedDirtyRegion.clear();
}
if(lcblk->getQueuedCount()) {
mFlinger->signalEvent();
}
/*
如果脏区域不为空,则需要绘制成纹理,reloadTexture将绘制一张纹理保存在
mTextures数组中,里边涉及很多OpenGL的操作,读者有兴趣可以自己研究。
*/
if(!mPostedDirtyRegion.isEmpty()) {
reloadTexture( mPostedDirtyRegion );
}
}
~~~
我们知道,Layer的lockPageFlip将根据FrontBuffer的内容生成一张纹理。那么,unlockPageFlip会做些什么呢?
(2)unlockPageFlip的分析
unlockPageFlip的代码如下所示:
**SurfaceFlinger.cpp**
~~~
void SurfaceFlinger::unlockPageFlip(constLayerVector& currentLayers)
{
constGraphicPlane& plane(graphicPlane(0));
constTransform& planeTransform(plane.transform());
size_tcount = currentLayers.size();
sp<LayerBase> const* layers = currentLayers.array();
for(size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer = layers[i];
//调用每个显示层的unlockPageFlip,Layer的unlockPageFlip主要做一些
//区域的清理工作,读者可以自己看看。
layer->unlockPageFlip(planeTransform, mDirtyRegion);
}
}
~~~
(3)handlePageFlip的总结
handlePageFlip的工作其实很简单,以Layer类型为例来总结一下:
各个Layer需要从FrontBuffer中取得新数据,并生成一张OpenGL中的纹理。纹理可以看做是一个图片,这个图片的内容就是FrontBuffer中的图像。
现在每一个Layer都准备好了新数据,下一步的工作当然就是绘制了。来看handleRepaint函数。
3. 分析handleRepaint函数
handleRepaint函数的代码如下所示:
**SurfaceFlinger.cpp**
~~~
void SurfaceFlinger::handleRepaint()
{
mInvalidRegion.orSelf(mDirtyRegion);
if(mInvalidRegion.isEmpty()) {
return;
}
......
constDisplayHardware& hw(graphicPlane(0).displayHardware());
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
uint32_t flags = hw.getFlags();
if((flags & DisplayHardware::SWAP_RECTANGLE) ||
(flags & DisplayHardware::BUFFER_PRESERVED))
{
......//计算mDirtyRegion
}
// 在脏区域上进行绘制
composeSurfaces(mDirtyRegion);
mDirtyRegion.clear();
}
~~~
其中,composeSurfaces将不同的显示层内容进行混合,其实就是按Z轴的顺序由里到外依次绘制。当然,最后绘制的数据有可能遮盖前面绘制的数据,代码如下所示:
**SurfaceFlinger.cpp**
~~~
void SurfaceFlinger::composeSurfaces(constRegion& dirty)
{
constSurfaceFlinger& flinger(*this);
constLayerVector& drawingLayers(mDrawingState.layersSortedByZ);
constsize_t count = drawingLayers.size();
sp<LayerBase> const* const layers = drawingLayers.array();
for(size_t i=0 ; i<count ; ++i) {
const sp<LayerBase>& layer = layers[i];
const Region&visibleRegion(layer->visibleRegionScreen);
if(!visibleRegion.isEmpty()) {
const Region clip(dirty.intersect(visibleRegion));
if (!clip.isEmpty()) {
layer->draw(clip); //调用各个显示层的layer函数
}
}
}
}
~~~
draw函数在LayerBase类中实现,代码如下所示:
**LayerBase.cpp**
~~~
void LayerBase::draw(const Region& inClip)const
{
......
glEnable(GL_SCISSOR_TEST);
onDraw(clip);//调用子类的onDraw函数
}
~~~
至于Layer是怎么实现这个onDraw函数的,代码如下所示:
**Layer.cpp**
~~~
void Layer::onDraw(const Region& clip) const
{
intindex = mFrontBufferIndex;
if(mTextures[index].image == EGL_NO_IMAGE_KHR)
index = 0;
GLuint textureName = mTextures[index].name;
....
Region holes(clip.subtract(under));
if(!holes.isEmpty()) {
clearWithOpenGL(holes);
}
return;
}
//index是FrontBuffer对应生成的纹理,在lockPageFlip函数中就已经生成了。
drawWithOpenGL(clip,mTextures[index]);//将纹理画上去,里面有很多和OpenGL相关内容
}
~~~
drawWithOpenGL函数由LayerBase实现,看它是不是使用了这张纹理,代码如下所示:
**LayerBase.cpp**
~~~
void LayerBase::drawWithOpenGL(const Region&clip, const Texture& texture) const
{
constDisplayHardware& hw(graphicPlane(0).displayHardware());
constuint32_t fbHeight = hw.getHeight();
constState& s(drawingState());
//validateTexture函数内部将绑定指定的纹理
validateTexture(texture.name);
//下面就是OpenGL操作函数了
glEnable(GL_TEXTURE_2D);
......
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
//坐标旋转
switch(texture.transform) {
case HAL_TRANSFORM_ROT_90:
glTranslatef(0, 1, 0);
glRotatef(-90, 0, 0, 1);
break;
case HAL_TRANSFORM_ROT_180:
glTranslatef(1, 1, 0);
glRotatef(-180, 0, 0, 1);
break;
case HAL_TRANSFORM_ROT_270:
glTranslatef(1, 0, 0);
glRotatef(-270, 0, 0, 1);
break;
}
if (texture.NPOTAdjust) {
//缩放处理
glScalef(texture.wScale, texture.hScale, 1.0f);
}
//使能纹理坐标
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//设置顶点坐标
glVertexPointer(2, GL_FIXED, 0, mVertices);
//设置纹理坐标
glTexCoordPointer(2, GL_FIXED, 0, texCoords);
while(it != end) {
const Rect& r = *it++;
const GLint sy = fbHeight - (r.top + r.height());
//裁剪
glScissor(r.left, sy, r.width(), r.height());
//画矩形
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
//禁止纹理坐标
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
~~~
纹理绑定是OpenGL的常用函数,其代码如下所示。
**LayerBase.cpp**
~~~
void LayerBase::validateTexture(GLinttextureName) const
{
//下面这个函数将绑定纹理
glBindTexture(GL_TEXTURE_2D, textureName);
......//其他一些设置
}
~~~
handleRepaint这个函数基本上就是按Z轴的顺序对每一层进行重绘,重绘的方法就是使用OpenGL。
我在Android平台上有几个月的OpenGL开发经历,还谈不上很深刻,其中的一些资料,希望能够给感兴趣的读者提供参考。
1)OpenGL的入门教材当选NeHe的资料,大略看前几章即可。
2) Android平台上关于OpenGL ES的开发,有一篇很详细的Word文档叫《OpenGL ESTutorial for Android》。该文详细描述了在Android平台上进行OpenGL开发的流程。大家可跟着这篇教材,在模拟器上做一些练习。那里面涉及到的一些基础知识,从前面介绍的入门教材中可以学到。
3)有了前面两点的基础后,就需要对整个OpenGL有比较完整深入的了解了。我在那时所看的书是《OpenGL Programming Guide (7th Edition)》。该书很厚,有1000多页。里面有一些内容可能与工作无涉,只要大概知道有那回事就行了,暂时不必深入学习,等需要时再进一步学习并运用。我在开发的项目中曾用到的光照、雾化等效果,都是之前先知道有这个东西,后来在项目中才逐渐学习运用的。
4)嵌入式平台上用的其实是OpenGL ES。这里,还有一本书叫《OpenGL ES 2.0 Programming Guide》,它介绍了OpenGL ES的开发,读者可认真修习。
5)在Android SDK文档中,对OpenGL API的描述只寥寥数语。怎么办?由于它使用了J2ME中的javax.microedition.khronos.opengles包,所以J2ME的SDK文档中对OpenGL的API有着非常详细的描述,读者手头应该要有一个J2ME的文档。
6)如果想做深入开发,就不得不学习计算机图形学了。我后来买了书,可惜没时间学了。
4. unlockClients和postFrameBuffer的分析
在绘制完图后,还有两项工作需要做,一个涉及unlockClients函数,另外一个涉及postFrameBuffer函数,这两个函数分别干了什么呢?unlockClients的代码如下所示:
**SurfaceFlinger.cpp**
~~~
void SurfaceFlinger::unlockClients()
{
constLayerVector& drawingLayers(mDrawingState.layersSortedByZ);
constsize_t count = drawingLayers.size();
sp<LayerBase> const* const layers = drawingLayers.array();
for (size_t i=0 ; i<count ; ++i) {
const sp<LayerBase>& layer = layers[i];
layer->finishPageFlip();
}
}
~~~
再看Layer的finishPageFlip函数,代码如下所示:
**Layer.cpp**
~~~
void Layer::finishPageFlip()
{
//释放FrontBufferIndex
status_t err = lcblk->unlock( mFrontBufferIndex );
}
~~~
原来,unlockClients会释放之前占着的FrontBuffer的索引号。下面看最后一个函数postFrameBuffer,代码如下所示:
**SurfaceFlinger.cpp**
~~~
void SurfaceFlinger::postFramebuffer()
{
if(!mInvalidRegion.isEmpty()) {
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const nsecs_t now = systemTime();
mDebugInSwapBuffers = now;
//调用这个函数后,混合后的图像就会传递到屏幕中显示了
hw.flip(mInvalidRegion);
mLastSwapBufferTime = systemTime() - now;
mDebugInSwapBuffers = 0;
mInvalidRegion.clear();
}
}
~~~
flip将调用在DisplayHardware一节中提到的eglSwapBuffer函数,来完成FrameBuffer的PageFlip操作,代码如下所示:
**DisplayHardware.cpp**
~~~
void DisplayHardware::flip(const Region&dirty) const
{
checkGLErrors();
EGLDisplay dpy = mDisplay;
EGLSurface surface = mSurface;
......
if(mFlags & PARTIAL_UPDATES) {
mNativeWindow->setUpdateRectangle(dirty.getBounds());
}
mPageFlipCount++;
eglSwapBuffers(dpy, surface);//PageFlipping,此后图像终于显示在屏幕上了!
}
~~~
- 前言
- 第1章 阅读前的准备工作
- 1.1 系统架构
- 1.1.1 Android系统架构
- 1.1.2 本书的架构
- 1.2 搭建开发环境
- 1.2.1 下载源码
- 1.2.2 编译源码
- 1.3 工具介绍
- 1.3.1 Source Insight介绍
- 1.3.2 Busybox的使用
- 1.4 本章小结
- 第2章 深入理解JNI
- 2.1 JNI概述
- 2.2 学习JNI的实例:MediaScanner
- 2.3 Java层的MediaScanner分析
- 2.3.1 加载JNI库
- 2.3.2 Java的native函数和总结
- 2.4 JNI层MediaScanner的分析
- 2.4.1 注册JNI函数
- 2.4.2 数据类型转换
- 2.4.3 JNIEnv介绍
- 2.4.4 通过JNIEnv操作jobject
- 2.4.5 jstring介绍
- 2.4.6 JNI类型签名介绍
- 2.4.7 垃圾回收
- 2.4.8 JNI中的异常处理
- 2.5 本章小结
- 第3章 深入理解init
- 3.1 概述
- 3.2 init分析
- 3.2.1 解析配置文件
- 3.2.2 解析service
- 3.2.3 init控制service
- 3.2.4 属性服务
- 3.3 本章小结
- 第4章 深入理解zygote
- 4.1 概述
- 4.2 zygote分析
- 4.2.1 AppRuntime分析
- 4.2.2 Welcome to Java World
- 4.2.3 关于zygote的总结
- 4.3 SystemServer分析
- 4.3.1 SystemServer的诞生
- 4.3.2 SystemServer的重要使命
- 4.3.3 关于 SystemServer的总结
- 4.4 zygote的分裂
- 4.4.1 ActivityManagerService发送请求
- 4.4.2 有求必应之响应请求
- 4.4.3 关于zygote分裂的总结
- 4.5 拓展思考
- 4.5.1 虚拟机heapsize的限制
- 4.5.2 开机速度优化
- 4.5.3 Watchdog分析
- 4.6 本章小结
- 第5章 深入理解常见类
- 5.1 概述
- 5.2 以“三板斧”揭秘RefBase、sp和wp
- 5.2.1 第一板斧--初识影子对象
- 5.2.2 第二板斧--由弱生强
- 5.2.3 第三板斧--破解生死魔咒
- 5.2.4 轻量级的引用计数控制类LightRefBase
- 5.2.5 题外话-三板斧的来历
- 5.3 Thread类及常用同步类分析
- 5.3.1 一个变量引发的思考
- 5.3.2 常用同步类
- 5.4 Looper和Handler类分析
- 5.4.1 Looper类分析
- 5.4.2 Handler分析
- 5.4.3 Looper和Handler的同步关系
- 5.4.4 HandlerThread介绍
- 5.5 本章小结
- 第6章 深入理解Binder
- 6.1 概述
- 6.2 庖丁解MediaServer
- 6.2.1 MediaServer的入口函数
- 6.2.2 独一无二的ProcessState
- 6.2.3 时空穿越魔术-defaultServiceManager
- 6.2.4 注册MediaPlayerService
- 6.2.5 秋风扫落叶-StartThread Pool和join Thread Pool分析
- 6.2.6 你彻底明白了吗
- 6.3 服务总管ServiceManager
- 6.3.1 ServiceManager的原理
- 6.3.2 服务的注册
- 6.3.3 ServiceManager存在的意义
- 6.4 MediaPlayerService和它的Client
- 6.4.1 查询ServiceManager
- 6.4.2 子承父业
- 6.5 拓展思考
- 6.5.1 Binder和线程的关系
- 6.5.2 有人情味的讣告
- 6.5.3 匿名Service
- 6.6 学以致用
- 6.6.1 纯Native的Service
- 6.6.2 扶得起的“阿斗”(aidl)
- 6.7 本章小结
- 第7章 深入理解Audio系统
- 7.1 概述
- 7.2 AudioTrack的破解
- 7.2.1 用例介绍
- 7.2.2 AudioTrack(Java空间)分析
- 7.2.3 AudioTrack(Native空间)分析
- 7.2.4 关于AudioTrack的总结
- 7.3 AudioFlinger的破解
- 7.3.1 AudioFlinger的诞生
- 7.3.2 通过流程分析AudioFlinger
- 7.3.3 audio_track_cblk_t分析
- 7.3.4 关于AudioFlinger的总结
- 7.4 AudioPolicyService的破解
- 7.4.1 AudioPolicyService的创建
- 7.4.2 重回AudioTrack
- 7.4.3 声音路由切换实例分析
- 7.4.4 关于AudioPolicy的总结
- 7.5 拓展思考
- 7.5.1 DuplicatingThread破解
- 7.5.2 题外话
- 7.6 本章小结
- 第8章 深入理解Surface系统
- 8.1 概述
- 8.2 一个Activity的显示
- 8.2.1 Activity的创建
- 8.2.2 Activity的UI绘制
- 8.2.3 关于Activity的总结
- 8.3 初识Surface
- 8.3.1 和Surface有关的流程总结
- 8.3.2 Surface之乾坤大挪移
- 8.3.3 乾坤大挪移的JNI层分析
- 8.3.4 Surface和画图
- 8.3.5 初识Surface小结
- 8.4 深入分析Surface
- 8.4.1 与Surface相关的基础知识介绍
- 8.4.2 SurfaceComposerClient分析
- 8.4.3 SurfaceControl分析
- 8.4.4 writeToParcel和Surface对象的创建
- 8.4.5 lockCanvas和unlockCanvasAndPost分析
- 8.4.6 GraphicBuffer介绍
- 8.4.7 深入分析Surface的总结
- 8.5 SurfaceFlinger分析
- 8.5.1 SurfaceFlinger的诞生
- 8.5.2 SF工作线程分析
- 8.5.3 Transaction分析
- 8.5.4 关于SurfaceFlinger的总结
- 8.6 拓展思考
- 8.6.1 Surface系统的CB对象分析
- 8.6.2 ViewRoot的你问我答
- 8.6.3 LayerBuffer分析
- 8.7 本章小结
- 第9章 深入理解Vold和Rild
- 9.1 概述
- 9.2 Vold的原理与机制分析
- 9.2.1 Netlink和Uevent介绍
- 9.2.2 初识Vold
- 9.2.3 NetlinkManager模块分析
- 9.2.4 VolumeManager模块分析
- 9.2.5 CommandListener模块分析
- 9.2.6 Vold实例分析
- 9.2.7 关于Vold的总结
- 9.3 Rild的原理与机制分析
- 9.3.1 初识Rild
- 9.3.2 RIL_startEventLoop分析
- 9.3.3 RIL_Init分析
- 9.3.4 RIL_register分析
- 9.3.5 关于Rild main函数的总结
- 9.3.6 Rild实例分析
- 9.3.7 关于Rild的总结
- 9.4 拓展思考
- 9.4.1 嵌入式系统的存储知识介绍
- 9.4.2 Rild和Phone的改进探讨
- 9.5 本章小结
- 第10章 深入理解MediaScanner
- 10.1 概述
- 10.2 android.process.media分析
- 10.2.1 MSR模块分析
- 10.2.2 MSS模块分析
- 10.2.3 android.process.media媒体扫描工作的流程总结
- 10.3 MediaScanner分析
- 10.3.1 Java层分析
- 10.3.2 JNI层分析
- 10.3.3 PVMediaScanner分析
- 10.3.4 关于MediaScanner的总结
- 10.4 拓展思考
- 10.4.1 MediaScannerConnection介绍
- 10.4.2 我问你答
- 10.5 本章小结