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之间的框架图:

从底层往上看:
1)linux内核提供统一的设备驱动,/dev/graphics/fb*
2) Android HAL 提供2个接口 Gralloc & fb
fb 负责打开framebuffer,提供接口操作。gralloc负责管理帧缓冲区的分配和释放。
composer是HAL中另一个重要的功能,它主要是给厂商定制UI合成。SurfaceFlinger中负责HWComposer会用到这个功能。
而且关键是HWComposer还负责产生VSync信号,这是本期SurfaceFlinger的重点。
3)由于OpenGL是一套通用的库(大部分就是接口),所以它需要一个本地的实现。andorid平台OpenGL有2个本地窗口,FrameBufferNativeWindow & Surface。
4)OpenGL可以有软件 或者依托于硬件实现,具体的运行状态,就是由EGL来配置。
5)SurfaceFlinger持有一个成员数组mDisplays来支持各种显示设备。DisplayDevices在初始化的时候调用EGL来搭建OpenGL的环境。
 

2.Android的硬件接口HAL

HAL需要满足android系统和厂商的要求

2.1硬件接口的抽象

从面向对象角度来讲,接口的概念就是由C++非常容易实现,但是HAL很多代码是C语言描述的。
这就需要一种技巧来实现面向对象。
定义一种结构,子类的成员变量第一个类型是父类的结构就可以了。抽象方法可以用函数指针来实现。
其实这个就是C++多态实现的基本原理,具体可参考《深入理解C++对象模型》

2.2接口的稳定性

Android已经把各个硬件都接口都统一定义在:

libhardware/include/hardware/ 具体代码可以参考:https://github.com/CyanogenMod/android_hardware_libhardware/tree/cm-12.0/include/hardware

3.Android显示设备:Gralloc &  FrameBuffer

FrameBuffer是linux环境下显示设备的统一接口。从而让用户设备不需要做太多的操作,就可以适配多种显示设备。
FramwBuffer本质上就是一套接口。android系统不会直接操作显示驱动,而通过HAL层来封装。而HAL中操作驱动的模块就是
gralloc。

3.1Gralloc模块的加载

gralloc通过FrameBufferNativeWindow 来加载的:
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设备名是否正确。

分配dev的空间,这是一个壳。
然后初始化dev。
提供fb的核心接口
内存映射
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个。

一个是面向管理者(SurfaceFlinger)的 FramebufferNativeWindow
另一个是面像APP的,surface。
先来看第一种:
首先看下定义的地方:
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内存的。它到底是什么呢?

 先来看看从ViewRootImpl到获取surface的过程。
ViewRootImpl持有一个java层的surface对象,开始是空的。
后续的流程见上面的流程图。也就是-说ViewRootImpl持有的surface对象,最终是对SurfaceComposerClient的创建的surface的一个“引用”。
由此分析可以看到 一个ISurfaceClient->ISurfaceComposerClient->IGraphicBufferProducer.当然binder需要一个实名的server来注册。
在ServiceManager中可以看到,这些服务查询的是“SurfaceFlinger”。
也就是,这些东东都是SurfaceFlinger的内容。
SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(),

SurfaceFlinger是BnSurfaceComposer的一个子类。也就是ISurfaceComposer的一个实现。

surface虽然是为app层服务的,但是本质上还是由SurfaceFlinger来管理的。

SurfaceFlinger怎么创建和管理surface,需要通过BufferQueue,将在下一篇讨论。

参考:

《深入理解android内核设计思想》 林学森

 

android Gui系统之SurfaceFlinger(1)---SurfaceFlinger概论的更多相关文章

  1. 图解Android - System Service 概论 和 Android GUI 系统

    通过 图解Android - Binder 和 Service 一文中,我们已经分析了Binder 和 Service的工作原理.接下来,我们来简要分析Android 系统里面都有哪些重要的Servi ...

  2. 图解Android - Android GUI 系统 (1) - 概论

    Android的GUI系统是Android最重要也最复杂的系统之一.它包括以下部分: 窗口和图形系统 - Window and View Manager System. 显示合成系统 - Surfac ...

  3. Android GUI系统

    图解Android - Android GUI 系统 (1) - 概论 图解Android - Android GUI 系统 (2) - 窗口管理系统 图解Android - Android GUI ...

  4. 图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)

    Android 的窗口管理系统 (View, Canvas, WindowManager) 在图解Android - Zygote 和 System Server 启动分析一 文里,我们已经知道And ...

  5. 图解Android - Android GUI 系统 (5) - Android的Event Input System

    Android的用户输入处理 Android的用户输入系统获取用户按键(或模拟按键)输入,分发给特定的模块(Framework或应用程序)进行处理,它涉及到以下一些模块: Input Reader: ...

  6. android Gui系统之SurfaceFlinger(1)---SurfaceFlinger概论【转】

    转自:https://www.cnblogs.com/deman/p/5584198.html 阅读目录 1.OpenGL & OpenGL ES 2.Android的硬件接口HAL 3.An ...

  7. android Gui系统之SurfaceFlinger(3)---SurfaceFlinger

    7.SurfaceFlinger SurfaceFlinger在前面的篇幅了,多有涉及. SurfaceFlinger是GUI刷新UI的核心,所以任何关于SurfaceFlinger的改进都会对and ...

  8. android Gui系统之SurfaceFlinger(4)---Vsync(1)

    8.Vsync 8.1概论 VSYNC(Vertical Synchronization)是一个相当古老的概念,对于游戏玩家,它有一个更加大名鼎鼎的中文名字—-垂直同步. “垂直同步(vsync)”指 ...

  9. android Gui系统之SurfaceFlinger(5)---Vsync(2)

    9.Vsync第二部分 在上一篇中我们讲到,视图的刷新需要很多步骤, void SurfaceFlinger::handleMessageRefresh() { ATRACE_CALL(); preC ...

随机推荐

  1. .net IO异步和Producer/Consumer队列实现一分钟n次http请求

    简介 最近工作中有一个需求:要求发送http请求到某站点获取相应的数据,但对方网站限制了请求的次数:一分钟最多200次请求. 搜索之后,在stackoverflow网站查到一个类似的问题..但里面用到 ...

  2. .NET invoke NetSuite Restlet

    Please indicate the source if you need to repost. Restlet allows programmers to use the http request ...

  3. Spring mvc web.xml中 urlpatten的配置问题

    在使用spring mvc 是我们会配置spring 的DispatcherServlet作为请求的转发器. <servlet> <servlet-name>spring< ...

  4. java 克隆

    1. About Java中, 对于基本数据类型可以使用"=" 来克隆,此时两个对象除了相等是没有任何关系的; 而对于引用类型, 却不能简单地使用"="来克隆, ...

  5. 每天一命令 git checkout

    检出 checkout  是git常用命令之一.主要用于创建切换分支,覆盖本地修改等 git checkout 用于显示工作区,暂存区,版本库中文件的区别 git checkout -b branch ...

  6. 设计一个较好的框架的难点之一--API兼容性的设计

    设计一个好的框架和设计一个好的软件一样,需要考虑的方面很多,比如扩展性.性能.用户体验.稳健性等等,视不同的场景,每个点都可能导致成败,但他们通常并不是老板们关心的,因为在大部分情况下,他们通常都没有 ...

  7. SharePoint 2010商业智能组件

    Microsoft Office SharePoint Server (MOSS) 2007中,就已经提供了很多支持商业智能的能力.其中主要的组件包含Excel Services, Reporting ...

  8. 带给你灵感:30个超棒的 SVG 动画展示【下篇】

    前端开发人员和设计师一般使用 CSS 来创建 HTML 元素动画.然而,由于 HTML 在创建图案,形状,和其他方面的局限性,它们自然的转向了 SVG,它提供了更多更有趣的能力.借助 SVG,我们有更 ...

  9. 发测试 HTML/FILE/MYSQL/动态 20151120

    NilCMS几种页面输出方式: 1.直接生成html.不进行php处理. 2.生成文件缓存.针对于URL中单个目录文件过多,不利于管理.只进行PHP处理,不连接mysql. 3.生成mysql缓存.数 ...

  10. What is research (1)

    This abstract tells me a lot of stories about itself. Here I want to discuss two stories about it. I ...