android Gui系统之SurfaceFlinger(1)---SurfaceFlinger概论
GUI 是任何系统都很重要的一块。
android GUI大体分为4大块。
1)SurfaceFlinger
2)WMS
3)View机制
4)InputMethod
这块内容非常之多,但是理解后,可以触类旁通,其实现在主流的系统,包括andorid,ios在构架上,都是有很多相识之处。
我们先来讲SurfaceFlinger
1.OpenGL & OpenGL ES
OPenGL ES 是android系统绘画的基础。关于OpenGL部分,可以百度了解下。
先来看一个OpenGL & SurfaceFlinger之间的框架图:

2.Android的硬件接口HAL
2.1硬件接口的抽象
2.2接口的稳定性
Android已经把各个硬件都接口都统一定义在:
libhardware/include/hardware/ 具体代码可以参考:https://github.com/CyanogenMod/android_hardware_libhardware/tree/cm-12.0/include/hardware
3.Android显示设备:Gralloc & FrameBuffer
3.1Gralloc模块的加载
FramebufferNativeWindow::FramebufferNativeWindow()
: BASE(), fbDev(), grDev(), mUpdateOnDemand(false)
{
hw_module_t const* module;
if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == ) {
int stride;
int err;
int i;
err = framebuffer_open(module, &fbDev);
ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err)); err = gralloc_open(module, &grDev);
ALOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err)); // bail out if we can't initialize the modules
if (!fbDev || !grDev)
return; mUpdateOnDemand = (fbDev->setUpdateRect != ); // initialize the buffer FIFO
if(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS &&
fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){
mNumBuffers = fbDev->numFramebuffers;
} else {
mNumBuffers = MIN_NUM_FRAME_BUFFERS;
}
mNumFreeBuffers = mNumBuffers;
mBufferHead = mNumBuffers-; /*
* This does not actually change the framebuffer format. It merely
* fakes this format to surfaceflinger so that when it creates
* framebuffer surfaces it will use this format. It's really a giant
* HACK to allow interworking with buggy gralloc+GPU driver
* implementations. You should *NEVER* need to set this for shipping
* devices.
*/
#ifdef FRAMEBUFFER_FORCE_FORMAT
*((uint32_t *)&fbDev->format) = FRAMEBUFFER_FORCE_FORMAT;
#endif for (i = ; i < mNumBuffers; i++)
{
buffers[i] = new NativeBuffer(
fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
} for (i = ; i < mNumBuffers; i++)
{
err = grDev->alloc(grDev,
fbDev->width, fbDev->height, fbDev->format,
GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride); ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",
i, fbDev->width, fbDev->height, strerror(-err)); if (err)
{
mNumBuffers = i;
mNumFreeBuffers = i;
mBufferHead = mNumBuffers-;
break;
}
} const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
const_cast<int&>(ANativeWindow::minSwapInterval) =
fbDev->minSwapInterval;
const_cast<int&>(ANativeWindow::maxSwapInterval) =
fbDev->maxSwapInterval;
} else {
ALOGE("Couldn't get gralloc module");
} ANativeWindow::setSwapInterval = setSwapInterval;
ANativeWindow::dequeueBuffer = dequeueBuffer;
ANativeWindow::queueBuffer = queueBuffer;
ANativeWindow::query = query;
ANativeWindow::perform = perform; ANativeWindow::dequeueBuffer_DEPRECATED = dequeueBuffer_DEPRECATED;
ANativeWindow::lockBuffer_DEPRECATED = lockBuffer_DEPRECATED;
ANativeWindow::queueBuffer_DEPRECATED = queueBuffer_DEPRECATED;
}
FramebufferNativeWindow
我们继续深入看:
galloc的父类,最终是:
libhardware\include\hardware\hardware.h
typedef struct hw_module_methods_t {
/** Open a specific device */
int (*open)(const struct hw_module_t* module, const char* id,
struct hw_device_t** device); } hw_module_methods_t;
只有一个open方法,也就是所有的厂商都需要实现开启设备的方法。
看下fb的打开的代码:
libhardware\modules\gralloc\framebuffer.cpp
int fb_device_open(hw_module_t const* module, const char* name,
hw_device_t** device)
{
int status = -EINVAL;
if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
/* initialize our state here */
fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
memset(dev, , sizeof(*dev)); /* initialize the procs */
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = ;
dev->device.common.module = const_cast<hw_module_t*>(module);
dev->device.common.close = fb_close;
dev->device.setSwapInterval = fb_setSwapInterval;
dev->device.post = fb_post;
dev->device.setUpdateRect = ; private_module_t* m = (private_module_t*)module;
status = mapFrameBuffer(m);
if (status >= ) {
int stride = m->finfo.line_length / (m->info.bits_per_pixel >> );
int format = (m->info.bits_per_pixel == )
? (m->info.red.offset ? HAL_PIXEL_FORMAT_BGRA_8888 : HAL_PIXEL_FORMAT_RGBX_8888)
: HAL_PIXEL_FORMAT_RGB_565;
const_cast<uint32_t&>(dev->device.flags) = ;
const_cast<uint32_t&>(dev->device.width) = m->info.xres;
const_cast<uint32_t&>(dev->device.height) = m->info.yres;
const_cast<int&>(dev->device.stride) = stride;
const_cast<int&>(dev->device.format) = format;
const_cast<float&>(dev->device.xdpi) = m->xdpi;
const_cast<float&>(dev->device.ydpi) = m->ydpi;
const_cast<float&>(dev->device.fps) = m->fps;
const_cast<int&>(dev->device.minSwapInterval) = ;
const_cast<int&>(dev->device.maxSwapInterval) = ;
*device = &dev->device.common;
}
}
return status;
}
首先check设备名是否正确。
status = mapFrameBuffer(m);
然后是建立壳 & 核心间的关系。
这样就打开了fb设备。
在回到FrameBufferNativeWindow 可以看到:
err = framebuffer_open(module, &fbDev);
ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err)); err = gralloc_open(module, &grDev);
ALOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));
fb打开的驱动信息在fbDev,gralloc打开的信息在grDev中。
fbDev负责的是主屏幕,grDev负责图形缓冲去的分配和释放。
所以FrameBufferNativeWindow控制这SurfaceFlinger的基础。
4.FrameBufferNativeWindow
4.1FramebufferNativeWindow
在OpenGL中,我们不断提及本地窗口的概念,在Android中,native window一共由2个。
首先看下定义的地方:
class FramebufferNativeWindow
: public ANativeObjectBase<
ANativeWindow,
FramebufferNativeWindow,
LightRefBase<FramebufferNativeWindow> >
{
ANativeWindow是什么东西?
ANativeWindow是OpenGL 在android平台的显示类型。
所以FramebufferNativeWindow就是一种Open GL可以显示的类型。
FramebufferNativeWindow的构造函数上面已经贴出来了,进一步分析如下:
1)加载module,上面已经分析过了。
2)打开fb & gralloc,也已经分析过了。
3)根据fb的设备属性,获得buffer数。这个buffer后面会解释。
4)给每个buffer初始化,并分配空间。这里new NativeBuffer只是指定buffer的类型,或者分配了一个指针,但是没有分配内存,所以还需要alloc操作。
5)为本地窗口属性赋值。
目前buffer默认值是在2~3,后面会介绍3缓冲技术,就会用到3个buffer。
双缓冲技术:
把一组图画,画到屏幕上,画图是需要时间的,如果时间间隔比较长,图片就是一个一个的画在屏幕的,看上去就会卡。
如果先把图片放在一个缓冲buffer中,待全部画好后,把buffer直接显示在屏幕上,这就是双缓冲技术。
4.2dequeuebuffer
int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window,
ANativeWindowBuffer** buffer, int* fenceFd)
{
FramebufferNativeWindow* self = getSelf(window);
Mutex::Autolock _l(self->mutex);
framebuffer_device_t* fb = self->fbDev; int index = self->mBufferHead++;
if (self->mBufferHead >= self->mNumBuffers)
self->mBufferHead = ; // wait for a free non-front buffer
while (self->mNumFreeBuffers < ) {
self->mCondition.wait(self->mutex);
}
ALOG_ASSERT(self->buffers[index] != self->front); // get this buffer
self->mNumFreeBuffers--;
self->mCurrentBufferIndex = index; *buffer = self->buffers[index].get();
*fenceFd = -; return ;
}
代码不多,但是却是核心功能,通过它来获取一块可渲染的buffer。
1)获取FramebufferNativeWindow对象。为什么没有使用this 而是使用了传入ANativeWindow的方式,此处我们并不关心。
2)获得一个Autolock的锁,函数结束,自动解锁。
3)获取mBufferHead变量,这里自增,也就是使用下一个buffer,一共只有3个,(原因上面已经解释),所以循环取值。
4)如果没有可用的缓冲区,等待bufferqueue释放。一旦获取后,可用buffer就自减
5.Surface
Surface是另一个本地窗口,主要和app这边交互。注意:app层java代码无法直接调用surface,只是概念上surface属于app这一层的。
首先Surface是ANativeWindow的一个子类。
可以推测,surface需要解决如下几个问题:
1)面向上层(java层)提供画板。由谁来分配这块内存
2)与SurfaceFlinger是什么关系
Surface::Surface(
const sp<IGraphicBufferProducer>& bufferProducer,
bool controlledByApp)
sp<IGraphicBufferProducer>& bufferProducer 是分配surface内存的。它到底是什么呢?

SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(),
SurfaceFlinger是BnSurfaceComposer的一个子类。也就是ISurfaceComposer的一个实现。
surface虽然是为app层服务的,但是本质上还是由SurfaceFlinger来管理的。
SurfaceFlinger怎么创建和管理surface,需要通过BufferQueue,将在下一篇讨论。
参考:
《深入理解android内核设计思想》 林学森
android Gui系统之SurfaceFlinger(1)---SurfaceFlinger概论的更多相关文章
- 图解Android - System Service 概论 和 Android GUI 系统
通过 图解Android - Binder 和 Service 一文中,我们已经分析了Binder 和 Service的工作原理.接下来,我们来简要分析Android 系统里面都有哪些重要的Servi ...
- 图解Android - Android GUI 系统 (1) - 概论
Android的GUI系统是Android最重要也最复杂的系统之一.它包括以下部分: 窗口和图形系统 - Window and View Manager System. 显示合成系统 - Surfac ...
- Android GUI系统
图解Android - Android GUI 系统 (1) - 概论 图解Android - Android GUI 系统 (2) - 窗口管理系统 图解Android - Android GUI ...
- 图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)
Android 的窗口管理系统 (View, Canvas, WindowManager) 在图解Android - Zygote 和 System Server 启动分析一 文里,我们已经知道And ...
- 图解Android - Android GUI 系统 (5) - Android的Event Input System
Android的用户输入处理 Android的用户输入系统获取用户按键(或模拟按键)输入,分发给特定的模块(Framework或应用程序)进行处理,它涉及到以下一些模块: Input Reader: ...
- android Gui系统之SurfaceFlinger(1)---SurfaceFlinger概论【转】
转自:https://www.cnblogs.com/deman/p/5584198.html 阅读目录 1.OpenGL & OpenGL ES 2.Android的硬件接口HAL 3.An ...
- android Gui系统之SurfaceFlinger(3)---SurfaceFlinger
7.SurfaceFlinger SurfaceFlinger在前面的篇幅了,多有涉及. SurfaceFlinger是GUI刷新UI的核心,所以任何关于SurfaceFlinger的改进都会对and ...
- android Gui系统之SurfaceFlinger(4)---Vsync(1)
8.Vsync 8.1概论 VSYNC(Vertical Synchronization)是一个相当古老的概念,对于游戏玩家,它有一个更加大名鼎鼎的中文名字—-垂直同步. “垂直同步(vsync)”指 ...
- android Gui系统之SurfaceFlinger(5)---Vsync(2)
9.Vsync第二部分 在上一篇中我们讲到,视图的刷新需要很多步骤, void SurfaceFlinger::handleMessageRefresh() { ATRACE_CALL(); preC ...
随机推荐
- WinForm GDI+ 资料收集
UI(User Interface)编程在整个项目开发过程中是个颇为重要的环节,任何好的解决方案若没有良好的用户界面呈现给最终用户,那么就算包含了最先进的技术也不能算是好程序.UI编程体现在两个方面, ...
- 基础复习 关于JS
1,js是一门解释型语言,无需编译,编写js要知道当前对象有什么成员,未必所有成员都能点出来. 2,js大小写敏感,严格区分大小写. 3,弱类型语言,声明用var,字符串推荐使用单引号. 4,==要先 ...
- iOS 阶段学习第11天笔记(OC基础知识)
iOS学习(OC语言)知识点整理 一.OC基础知识 1)#import 用于导入头文件,预处理阶段加载引用,只加载一次. 2)OC 依赖于Foundation框架下的头文件Foundation.h, ...
- Android存储空间不足的解决办法
安装应用时,有时会出现错误Installation error: INSTALL_FAILED_INSUFFICIENT_STORAGE,这是存储空间不足的错误,这时就只能将应用安装到SD卡,在And ...
- Delphi iOS 开启文件共享 UIFileSharingEnabled
Apple 在 iOS 提供了文件共享(FileSharing)功能,让 App 有一个对外窗口的目录,透过 iTunes 可以任意管理这个目录的文档内容(可拖入文档,也能将文档拖出备份). 如果 A ...
- 设置Xshell中支持中文
执行echo $LANG命令输出的是当前的编码方式,执行locale命令得到系统中所有可用的编码方式.要让Xshell不显示乱码,则要将编码方式改为UTF-8. 在Xshell中[file]-> ...
- 第 12 章 CSS 入门
学习要点: 1.使用 CSS 2.三种方式 3.层叠和继承 主讲教师:李炎恢 本章主要探讨 HTML5 中 CSS(层叠样式表),它是用来对 HTML 文档外观的表现形式进行排版和格式化. 一.使用 ...
- Android提升篇系列:adb无法识别MX5等特殊机型
发现自己Ubuntu系统adb无法识别魅族 mx5机型.操作具体如下(其他机型依然适用): 一.Ubuntu环境 1.查看自己当前设备的idVendor lsusb命令直接查看当前usb设别列表,找到 ...
- PowerDesigner
.PowerDesigner使用MySQL的auto_increment ◇问题描述: PD怎样能使主键id使用MySQL的auto_increment呢? ◇解决方法: 打开table p ...
- Java基础学习-- 继承 的简单总结
代码参考:Java基础学习小记--多态 为什么要引入继承? 还是做一个媒体库,里面可以放CD,可以放DVD.如果把CD和DVD做成两个没有联系的类的话,那么在管理这个媒体库的时候,要单独做一个添加CD ...