Android图形系统及GPU加速分析

Android图形系统及GPU加速分析
Android图形系统及GPU加速分析

Android图形系统及GPU加速分析

---西安交大智能交互与软件实验室

2013-5-7

一、Android图形系统简介

1.1Surface与SurfaceFlinger

对于现代的操作系统而言,流畅、精致的图形用户界面是构建优秀用户体验的重要手段。作为图形用户界面赖以存在的基础,图形系统已经成为操作系统的重要基础设施,特别对于移动设备而言,图形系统决定着该设备的整体体验与运行效率。

Android图形系统由两大组件构成:Surface和SurfaceFlinger。

Surface,又称绘图表面,代表应用程序需要显示在屏幕上的内容。Andorid系统中同时存在多个Surface,这些Surface可能会重叠、相互遮挡。

SurfaceFlinger负责Surface的叠加与合成,并把合成结果输出到屏幕上。同时,SurfaceFlinger为每一个Surface建立一个绘图缓冲区队列,用于存储Surface绘制的图像。

Android图形系统的总体结构如下:

图1Android图形系统总体结构

1.2Surface与SurfaceFlinger的交互过程

Surface与SurfaceFlinger的交互主要集中于当Surface需要更新的时候。交互过程如图2所示:

图2Surface与SurfaceFlinger的交互过程

首先,当Surface需要更新的时候,向SurfaceFlinger申请一块绘图缓冲区;之后,Surface 就在这块缓冲区上绘图;绘图完成后,Surface把缓冲区归还给SurfaceFlinger,并通知SurfaceFlinger重新合成各个Surface;SurfaceFlinger接收到合成请求后,合成并重绘需要重绘的Surface,并输出给显示设备,从而使屏幕上呈现最新的界面。

1.3图形系统的效率提升

作为Android系统的关键组件,图形系统的运行效率直接影响着用户体验,而且关乎系统的整体效率。Android系统采取如下措施提升图形系统的效率:

1.共享缓冲区

2.使用GPU加速图形绘制与叠加

下面,就分别分析Android图形系统对缓冲区的管理和对GPU的使用。

二、缓冲区管理

2.1Gralloc

为了便于使用,并隔离底层硬件的变化,向上提供统一的接口,Android在其HAL层为其图形系统提供了gralloc(即Graphic Alloc)模块,负责图像缓冲区的分配、映射和回收。它可以从Andorid匿名共享内存(以下简称AShm设备)和图形设备(Framebuffer设备,以下

简称fb设备)的存储区中分配缓冲区,并且可以把缓冲区映射到不同的进程中。

Ashm设备的存储区位于系统内存中,它的容量只受系统内存大小的限制。

Framebuffer设备的存储区位于显示设备的内存(即显存),或者位于系统内存的一块特定区域,这里统称为显存。显示设备可以直接访问显存,但是受技术和成本的限制,相对于系统内存来说,其容量往往较小。

注意,这两个存储区是不相交的,它们之间传递数据只能逐位复制。

Gralloc向外提供了3个主要的数据结构及其接口,他们的关系如下:

图3Gralloc数据结构及其接口

Gralloc是作为HAL层的一个模块运行的,所以其必须遵守HAL层的规范,即继承并实现代表HAL模块的hw_module_t和代表设备的hw_device_t。有关Android HAL的详细信息,请参考资料2。

作为分配图像缓冲区的模块,gralloc应该提供缓冲区分配和回收的机制;由于图像缓冲区会被不同的进程使用,gralloc还应该提供把缓冲区映射到特定进程的机制;为了保证多个进程的有序访问,gralloc必须提供锁机制;同时,gralloc还应该能够把缓冲区提交给fb设备,用于显示保存在其中的图像。

gralloc模块的实现如下:

gralloc_module_t:代表gralloc模块,并提供了进程映射和锁机制。其中:int registerBuffer(gralloc_module_t const*thiz,buffer_handle_t h)

会把h代表的缓冲区映射到调用者进程;

int unregisterBuffer(gralloc_module_t const*thiz,buffer_handle_t h)执行相反的操作,即从调用者进程解除映射;

int lock(gralloc_module_t*thiz,buffer_handle_t h,int usage,int l,int t,int w,int h,

void**vaddr)

会锁定h缓冲区中的左上角为(l,t),宽为w,高为h的区域,并把该区域的起始地址保存在vaddr中;

int unlock(gralloc_module_t*thiz,buffer_handle_t h)

用于解锁h代表的缓冲区。

alloc_device_t代表用于分配缓冲区的设备,它提供缓冲区分配与回收的功能,其中:int alloc(alloc_device_t*thiz,int w,int h,int format,int usage,buffer_handle_t*h,

int*stride)

用于分配符合需求(宽、高、格式等)的缓冲区,并保存在h中;

int free(alloc_device_t*thiz,buffer_handle_t h)

用于释放h所代表的缓冲区。

framebuffer_device_t代表fb设备,它提供提交缓冲区的功能,其中:

int post(framebuffer_device_t*thiz,buffer_handle_t buffer)

用于向fb设备提交buffer所代表的缓冲区,之后,这个缓冲区中的内容就会被显示在屏幕上。

关于gralloc详细的详细信息,可以参考资料3。

2.2缓冲区与缓冲区队列

2.2.1缓冲区分类

Android图形系统中,缓冲区主要用于存储绘图结果,可分为两类:

1.Surface的绘图缓冲区,用于保存每个Surface的绘图结果,称之为绘图缓冲区

2.SurfaceFlinger的合成缓冲区,用于保存经SurfaceFlinger叠加合成后的图像信息,称之为合成缓冲区。

理想情况下,缓冲区从fb设备的存储区中分配是最好的,因为这样的话,绘图和叠加完成后,显示设备就能直接把结果显示出来。但是,由于系统中会同时存在多个Surface,如果每一个Surface的绘图缓冲区都从fb设备中分配,那么就需要fb设备有很大的存储,这无疑会增加成本。

所以,Android就采取折中的办法,绘图缓冲区在系统内存中分配;由于合成缓冲区全局只需要一个(事实上,为了图像显示稳定,需要2个或3个,即便是这样,需要的存储空间也不大),所以合成缓冲区就从fb设备中分配。

Android图形系统分别使用GraphicBuffer和NativeWindow类描述这两类缓冲区,他们的关系如图4所示:

图4缓冲区类图

其中,基类ANativeWindowBuffer定义了缓冲区的基本属性,如起始地址(handle)、宽(width)、高(height)、格式(format)、用途(usage)。其中,usage决定了缓冲区是位于fb设备中,还是位于AShm设备中。当usage为1时,其位于fb设备中;否则,位于AShm 设备中。它的两个方法incStrong(...)和decStrong(...)用于增加和减少引用计数,所以ANativeWindowBuffer可以作为智能指针使用。

绘图缓冲区

GraphicBuffer表示绘图表面Surface使用的绘图缓冲区,它一般都是从AShm设备分配的,即其存储区位于内存,并可以在进程间共享。

由于GraphicBuffer所代表的缓冲区需要在应用程序进程和SurfaceFlinger进程中共享,所以GraphicBuffer需要提供锁机制保证缓冲区的互斥访问,这是通过lock和unlock方法实现的;由于应用程序每次更新的区域大小不固定,每次需要的缓冲区的大小就不同,所以,GraphicBuffer应该提供重新分配缓冲区存储空间的机制,这是通过reallocate方法实现的。各个方法介绍如下:

lock(uint32_t usage,void**vaddr)

用来锁定整个缓冲区,并把缓冲区的起始地址保存在vaddr变量中;

unlock()

用于解锁缓冲区;

reallocate(uint32_t w,uint32_t h,PixelFormat f,uint32_t usage)

用来重新分配存储。

同时,GraphicBuffer也继承于Flattenable,表示它可以被串行化,这样它就能通过Binder 在不同进程之间传递,它实现了Flattenable的getFlattenedSize(...)、getFdCount(...)、flatten(...)以及unflatten(...)方法,用于处理串行化和反串行化。

合成缓冲区

NativeWindow表示SurfaceFlinger保存合成结果的合成缓冲区。它没有在其父类的基础

上增加新的属性和方法。NativeWindow所代表的缓冲区是从Framebuffer设备中分配的。

2.2.2缓冲区队列

为了方便管理,Android把上述两类缓冲区组织成队列的形式,分别用Surface和FramebufferNativeWindow描述。他们的关系如图5所示:

图5缓冲区队列类图

其中,基类ANativeWindow定义了缓冲区队列的基本属性和方法。对于队列而言,最重要的就是出对和入队操作。ANativeWindow的重要方法说明如下:

dequeueBuffer(ANativeWindow*win,ANativeWindowBuffer**buf)

用于从队列中获取一个缓冲区,即出队,并保存在buf中。为了保持兼容性,ANativeWindow 使用C语言结构体定义的,dequeueBuffer是结构体中的一个函数指针,所以,需要第一个参数指定这个函数操作的对象,相当于C++中的this指针,下同。

lockBuffer(ANativeWindow*win,ANativeWindowBuffer*buf)

用于锁定一个buffer,这是为了保证buffer在不同进程中能被互斥的访问。

queueBuffer(ANativeWindow*win,ANativeWindowBuffer*buf)

用于向队列中归还buffer,即入队。

绘图缓冲区队列

Surface(及其父类SurfaceTextureClient)用于描述一个Surface需要的绘图缓冲区队列,注意区分两个Surface,前者是上图中的类,而后者是上文所说的绘图表面。

Surface和SurfaceTextureClient在ANativeWindow的基础上,将dequeueBuffer和lock 两个函数封装成一个lock函数;将queueBuffer封装成unlockAndPost函数。lock和unlockAndPost说明如下:

lock(SurfaceInfo*info,Region*dirty)

会从缓冲区队列获取并锁定一个缓冲区,并把这个缓冲区的的相关信息存储在info中(包括缓冲区的长、宽、格式、用途以及起始地址),上层应用就能在这个缓冲区中绘图了。

unlockAndPost()

用于解锁并发布上面用lock获取的缓冲区,并通知SurfaceFlinger刷新界面。这两个函数都是调用SurfaceTextureClient的lock和unlockAndPost函数实现的。

从类名可以看出,SurfaceTextureClient只是一个客户端,其服务端对应的是SurfaceTextureLayer,其中包括缓冲区类型为GraphicBuffer的缓冲区队列(队列大小目前为32)。SurfaceTextureLayer是一个Binder对象,在SurfaceFlinger中被初始化,每一个绘图表面都对应一个,其中的缓冲区在需要的时候分配。

SurfaceTextureClient和SurfaceTextureLayer分别位于应用程序进程和SurfaceFlinger进程,它们之间需要通过Android的进程间通信机制——Binder来相互通信。关于Binder的详细信息,请参考资料4。SurfaceTextureClient::mSurfaceTexture是SurfaceTextureLayer的Binder 代理,SurfaceTextureClient通过这个代理与SurfaceTextureLayer交互。

SurfaceTextureClient::lock(...)方法会调用自身的dequeueBuffer(...),其中会通过mSurfaceTexture从SurfaceTextureLayer中获取一个缓冲区并锁定,值得注意的是,因为SurfaceTextureLayer中的缓冲区都是在SurfaceFlinger进程中分配的,所以,在把缓冲区传递给应用程序进程中的SurfaceTextureClient时,系统会把缓冲区映射到应用程序进程中。

SurfaceTextureClient::unlockAndPost()方法调用自身的queueBuffer(...),其中会通过mSurfaceTexture向SurfaceTextureLayer归还缓冲区,之后,SurfaceTextureLayer会通知SurfaceFlinger更新图形界面。

SurfaceTextureLayer所包含的缓冲区GraphicBuffer最终会被会被用做OpenGL的纹理,这也是SurfaceTextureLayer和SurfaceTextureClient这样命名的原因。

合成缓冲区队列

FramebufferNativeWindow用于描述合成缓冲区队列。目前,其中buffers是指向NativeWindow类型数组,表示缓冲区,目前数组大小是2。它们的存储空间都来自于Framebuffer设备。

grDev是指向gralloc设备描述符alloc_device_t的指针,FramebufferNativeWindow使用它就能访问gralloc的alloc(...)和free(...)方法,从gralloc中分配存储,buffers就是在FramebufferNativeWindow初始化的时候,使用alloc(...)函数从gralloc中分配的。

fbDev是指向framebuffer设备描述符framebuffer_dvice_t的指针,它也是在gralloc中定义的,FramebufferNativeWindow使用它就能访问post(...)方法,从而向Framebuffer提交一个缓冲区,用于显示。

dequeueBuffer(...)和queueBuffer(...)分别用来获取和归还缓冲区。其中,dequeueBuffer 会从缓冲区buffers中取出空闲的buffer;queueBuffer最终会使用fbDev的post(...)方法,把

新的缓冲区提交给fb设备,用于显示。

2.3缓冲区的使用

绘图缓冲区的使用

Android应用程序在初始化的时候,系统会为其每一个可视化界面创建一个绘图缓冲区队列Surface,Surface会调用SurfaceFlinger的createSurface(...)方法,通知SurfaceFlinger建立于Surface对应的Layer对象。Layer对象在初始化的时候,会创建Surface绘图需要的缓冲区队列,具体的,就是创建前文提及的SurfaceTextureLayer对象,其中,就会初始化缓冲区队列。

因为Surface每次重绘需要的缓冲区的大小、格式等可能都会不一样,所以,缓冲区队列在初始化的时候并没有实际创建缓冲区对象GraphicBuffer。只有在Surface需要时,才会使用SurfaceTextureLayer::dequeueBuffer(...)获取一个buffer,此时,才会创建相应的GraphicBuffer缓冲区对象,其中,GraphicBuffer会根据Surface的需要,向gralloc模块申请需要的存储区,这快缓冲区来自于Ashm。因为Surface所在的应用程序和分配GraphicBuffer 的SurfaceFlinger不在同一个进程中,所以就需要把GraphicBuffer中缓冲区的地址映射到应用程序进程中,这个是通过上述gralloc_module_t中的的registerBuffer实现的。

合成缓冲区的使用

SurfaceFlinger会在初始化的时候创建EGL环境,EGL是OpenGL与本地图形系统的接口。SurfaceFlinger在使用eglCreateWindowSurface(...)初始化EGL的绘图表面时,将FramebufferNativeWindow设置为EGL绘图表面的缓冲区队列。其中的两个缓冲区会分别作为前台缓冲区(称为frontbuffer)和后台缓冲区(称为backbuffer),其中,frontbuffer是正在被显示的缓冲区,backbuffer是用于后台绘图的缓冲区。绘图完毕后,交换frontbuffer和backbuffer,之前的frontbuffer成为新的backbuffer,用于下一次绘图;之前的backbuffer成为新的frontbuffer,其中的图像数据被显示在屏幕上。这就实现了一个双缓冲机制,这种机制可以避免产生显示画面的抖动和残缺。

EGL在为OpenGL准备绘图环境时,使用FramebufferNativeWindow::dequeueBuffer(...)获取一个绘图缓冲区,作为backbuffer,之后OpenGL所绘制的图像信息就保存在这个缓冲区上;OpenGL绘图完成后使用eglSwapBuffers(...)交换缓冲区时,eglSwapBuffers(...)会使用FramebufferNativeWindow::queueBuffer()将backbuffer入队,在queueBuffer(...)中,会调用gralloc模块中framebuffer_device_t的post(…)函数将backbuffer与frontbuffer交换,这样backbuffer中的图像信息显示在屏幕;之后,eglSwapBuffers(...)又会使用dequeueBuffer()获取一个新的绘图缓冲区作为新的backbuffer,用于OpenGL的下一次绘制。

综上所述,SurfaceFlinger的结构图可以进一步细化为图6所示:

图6细化的结构图

三、使用GPU加速图形绘制与叠加

作为面向图形处理的芯片,GPU对图形处理做了专门优化,为了简化GPU的使用,业界提出了一个标准化的API——OpenGL。通过OpenGL,应用程序就能最大限度的发挥GPU 的强大处理能力。

Android系统也使用OpenGL加速图形系统效率,这体现在两方面:使用OpenGL加速Surface的绘制;使用OpenGL加速SurfaceFlinger对各个Surface的叠加。下面就从这两个方面分析。

3.1使用OpenGL加速图形的绘制

Android应用程序的界面是由多个可视化组件组成的,如Button(按钮)、文本框(TextView)等,这些可视化组件最终都会被绘制在Surface上。

之前,这些组件是使用Skia绘图库绘制到Surface上的。Skia是一个2D图形处理函数库,使用Skia可以绘制基本的图元,如点、线、面等,还可以绘制字型、进行坐标转换、绘制点阵图等。Skia是一个纯软件的解决方案,也就是说,使用它绘图时,绘图操作都是通过CPU执行的。

随着Android设备屏幕尺寸的增大和分辩率的不断提升,这种纯软件的解决方案会增加

了CPU的负担,导致图形界面卡顿、系统整体不流畅。

从Android3.0之后,Android开始使用OpenGL绘制控件,同时也保留了Skia。这样,在保证兼容性的前提下,Android可以发挥GPU的作用,加速图形系统的运行效率。

当一个组件需要重绘时,这些可视化控件的绘制都是从ViewRootImpl.java的draw方法开始的,其可以简化为:

void draw(boolean fullRedrawNeeded){

Surface surface=mSurface;

if(mAttachInfo.mHardwareRenderer!=null&&mAttachInfo.mHardwareRenderer.isEnabled()) attachInfo.mHardwareRenderer.draw(mView,attachInfo,this,mDirty);

else

drawSoftware(surface,attachInfo,yoff,scalingRequired,mDirty);

}

其中,drawSoftware就是使用Skia绘制,而attachInfo.mHardwareRenderer.draw使用OpenGL 绘制。

在使用Skia绘制时,drawSoftware(...)系统会调用2.2.2节中的Surface::lock(SurfaceInfo* info,Region*dirty)从SurfaceFlinger获取一个GraphicBuffer缓冲区,该缓冲区的信息存储在info中;之后,将这个缓冲区作为Skia的画布Canvas(具体类型为CompatibleCanvas)的绘图设备。之后,调用Skia绘图,绘图结果就保存在上述的GraphicBuffer缓冲区中。之后,使用Surface::unlockAndPost(),将保存有绘制结果的缓冲区重新放入SurfaceFlinger中的缓冲区队列中,并通知SurfaceFlinger重新合成界面。其中,Surface::unlockAndPost()又会使用SurfaceTextureClient::queueBuffer(…)完成上述功能。

如果打开了硬件加速(可以在应用程序的AndroidManifest.xml中设置),就会使用OpenGL,通过GPU加速绘图。

attachInfo.mHardwareRenderer是GLES20Renderer。它在初始化的时候,会初始化EGL 并创建绘图表面,并建立画板Canvas,和软件绘制方式不同,此处使用的画布的具体类型为GLES20Canvas,在其中绘制图像会被OpenGL加速。

在创建绘图表面的时候,会调用EGLImpl.eglCreateWindowSurface(EGLDisplay display, EGLConfig config,Object native_window,int[]attrib_list)),这个函数会检查第三个参数native_window的类型,只有第三个是SurfaceView或者SurfaceHolder类型的才可以,也就是说,目前,只有继承了SurfaceView或者SurfaceHolder的控件才能被GPU加速,一般的空间不能使用GPU加速。

如果类型正确,那么,该函数就会调用native_window.getSurface(),这个函数返回的就是2.2.2节中的Surface绘图缓冲区队列,之后,就会把Surface作为OpenGL的绘图表面,OpenGL的绘图结果就会保存在其中。

由2.2.2节对Surface的分析可知,其中的缓冲区都是GraphicBuffer类型的,位于Ashm,即内存中,并受SurfaceFlinger的管理。

所以,最终使用OpenGL绘图的结果保存在内存中,并在调用eglSwapBuffers()的时候,向SurfaceFlinger提交重绘请求。eglSwapBuffer()会调用EGL绘图表面的queueBuffer(…)把保存有绘制结果的缓冲区放入SurfaceFlinger的缓冲区队列中。根据上文,此处EGL的绘图表面就是Surface,所以会使用Surface::queueBuffer(…)完成缓冲区提交,由于Surface继承于SurfaceTextureClient而且没有重写queueBuffer(…),所以,和使用软件绘制一样,最终都是使用SurfaceTextureClient::queueBuffer(…)向SurfaceFlinger提交保存有绘制结果的缓冲区,之后,SurfaceFlinger就会叠加并输出这些缓冲区。

而且,不论是用Skia软件方式绘制,还是OpenGL硬件加速绘制,它们最终都会把绘

制好的图像信息存储在上述的GraphicBuffer中,并由SurfaceFlinger统一管理。

GLES20Renderer对应的画板是GLES20Canvas。它在初始化的时候,会创建在这个画板上绘图的渲染器OpenGLRenderer。OpenGLRenderer内部用OpenGL实现了常用的图形操作,像平移、旋转、缩放等,同时也实现了常用的画图操作,像画点,画线等。

同时,每一个控件的都会调用GLES20Renderer.createDisplayList(...)创建一个显示列表。控件需要重绘的时候,把绘制命令保存在显示列表中等待绘制。然后,在实际绘制的时候一次性把这些绘图命令传递给GPU。所以,使用显示列表就能以批处理的方式一次性处理一批请求,提高了效率。

attachInfo.mHardwareRenderer.draw(...)实际调用的就是GLES20Renderer.draw(...),其中会调用GLES20Canvas.drawDisplayList(...),继而调用与GLES20Canvas关联的渲染器OpenGLRenderer的drawDisplayList,其中会调用DisplayList的replay方法,从列表中取出绘图命令,最终使用OpenGLRenderer完成绘制工作。

3.2使用OpenGL加速Surface的叠加

在Surface绘制完图形并把绘图缓冲区交还给SurfaceFlinger后,各个缓冲区就保存着更新后的界面信息,SurfaceFlinger会把各个缓冲区中的图像信息叠加成一个完整的画面,并保存在合成缓冲区中,即backbuffer中。之后,通过交换backbuffer和frontbuffer,就能把结果显示出来。

由于各个Surface会相互重叠,而且Surface可能会是半透明的,所以,需要计算各个Surface对应的Layer的可视区域,之后,只用重绘这些可视区域就行;为了提高叠加和绘制的效率,可以把绘制结果作为Layer的纹理,使用OpenGL的纹理贴图功能加速叠加和绘制过程。

叠加过程可以简略描述如下:

1.把保存着Surface绘制结果的buffer作为该Surface对应的Layer的纹理对象;

2.计算需要每个Layer的可视区域;

3.通过OpenGL叠加各个Layer的可视区域,OpenGL会把Layer对应的纹理贴到

该区域上;

4.把绘制好的界面输出到屏幕上

下面,就逐一分析。

3.2.1把绘制结果作为纹理对象

SurfaceFlinger会调用每个layer的lockPageFlip(...),锁定该layer,其中又会调用与该layer 关联的SurfaceTexture中的updateTexImage(...)更新layer对应的纹理对象。SurfaceTexture用来把Surface对应的buffer转化为OpenGL的纹理。

updateTexImage(...)其可以简化为:

status_t SurfaceTexture::updateTexImage(BufferRejecter*rejecter){

BufferQueue::BufferItem item;

status_t err=mBufferQueue->acquireBuffer(&item);

if(err!=NO_ERROR)

return err;

int buf=item.mBuf;

GLeglImageOES image=

createImage(eglGetCurrentDisplay(),mEGLSlots[buf].mGraphicBuffer);

glBindTexture(mTexTarget,mTexName);

glEGLImageTargetTexture2DOES(mTexTarget,(GLeglImageOES)image);

}

其中,mBufferQueue就是SurfaceTextureLayer的实例。该函数首先用SurfaceTextureLayer::acquireBuffer(...)从layer对应的缓冲区队列中获取一个buffer,如果没有需要更新的buffer,就说明这个Layer没有变化,不需要更新纹理对象,那么直接返回即可。然后使用createImage(...)创建一个EGL图像,并将刚才获取的buffer中的数据作为该图像的内容;之后,使用glBindTexture设置OpenGL当前活动的纹理对象为mTexName,mTexName是在Layer初始化的时候使用glGenTexture创建的,每个Layer都有一个并且各不相同;之后,使用glEGLImageTargetTexture2DOES把刚才创建的image作为当前的活动纹理,即与mTexName关联起来。这样,保存有绘制结果的buffer就成为该layer的纹理对象了。

3.2.2计算可见区域

绑定纹理对象后,SurfaceFlinger开始计算每一个Layer的可见区域。Layer的可见区域就是能被显示在屏幕上的区域。由于同时存在多个layer,所以layer之间就会出现相互重叠的现象。当两个layer相互重叠时,下面layer的某些区域可能就会因为被遮挡而不可见。如果一个layer的可见区域与其需要重绘的区域没有交集,即需要重绘的部分是不可见的,那么就不需要重绘了。

一个layer的更新有可能导致layer之间重叠关系发生变化,所以需要重新计算每一个layer的可见区域。计算原理如下:

一个区域由3部分组成:不透明区域OP,透明区域TP以及半透明区域TL,很明显,透明区域TP是不可见的。

记layer0的全部区域为R,可见区域为V,那么V=R-TP。

当layer0被另外一个layer1覆盖时,记layer1覆盖在layer0上的区域为C。很明显,只用区域C中不透明区域OP会影响layer0被覆盖区域的可见性,即会让layer0的该区域不可见,所以,此时,现在layer0的可见区域就是layer0之前的可见区域去除被不透明区域覆盖的部分,即V=V-(V∩C.OP)。

所以,最终,一个layer的可见区域V=R-TP-(V∩C.OP),即在其全部区域中去除两部分区域:透明区域和被上层layer的不透明区域覆盖的区域。

这个过程只是两个layer的情况,多个layer的情况也类似,只是需要把所有上层layer 的可见区域都叠加起来,作为一个新的layer和下层layer叠加,这实际上又是两个layer在叠加。

SurfaceFlinger使用computeVisibleRegions(...)函数计算可见区域,原理和上面所述的一致,此处就不赘述了。

3.2.3叠加

计算完各个layer的可见区域后,就可以叠加各个layer的可见区域了。SurfaceFlinger 使用handleRepaint()函数完成绘制,其中主要使用SurfaceFlinger::composeSurfaces(...)叠加并

重绘界面。这是通过调用各个layer的draw方法完成的,而实际的绘图在Layer::onDraw方法中,其可以简化为:

void Layer::onDraw(const Region&clip){

glBindTexture(GL_TEXTURE_EXTERNAL_OES,mTextureName);

drawWithOpenGL(clip);

}

其中,参数clip就是这个layer的可见区域与全局脏区相交的区域。这个函数会先使用glBindTexture绑定该layer的纹理对象到当前OpenGL环境中,这之后OpenGL操作的都是这个纹理,直到下一次调用glBindTexture。值得注意的是,在handlePageFlip中,该layer 对应的应用程序所绘制的新的界面信息已经和纹理对象绑定,所以,之后就能通过opengl 的纹理贴图功能,把界面信息作为纹理贴到需要更新的区域,这是通过drawWithOpenGL(位于Layer的父类LayerBase)实现的,该函数可以简化为:

void LayerBase::drawWithOpenGL(const Region&clip)const{

...

glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glVertexPointer(2,GL_FLOAT,0,mVertices);

glTexCoordPointer(2,GL_FLOAT,0,texCoords);

glDrawArrays(GL_TRIANGLE_FAN,0,mNumVertices);

...

}

其中,mVertices是这个Layer的需要更新的区域的四个顶点坐标(更新区域为矩形);mNumVertices代表上述顶点的个数;texCoords表示纹理对象的四个顶点坐标,他们和mVertices是对应的。glVertexPointer和glTexCoordPointer两个函数分别指定了需要绘制的图形的顶点坐标和纹理的坐标。最后,glDrawArrays就绘制了一个矩形,其顶点坐标为mVertices,同时,OpenGL会自动把纹理(其中包含新界面信息)填充到这个矩形中,这样,该layer对应的应用程序的界面就更新了。

至此,所有需要更新的layer的像素信息都被OpenGL绘制在其backbuffer中了,即backbuffer中保存的就是最新的界面信息。而backbuffer是由gralloc模块从framebuffer设备中分配的。注意,这一步会涉及到内存复制,即把保存在ashm中的纹理信息复制到framebuffer。

3.2.4结果输出

上一步应经把最新的界面信息保存在backbuffer中了,所以只需要交换backbuffer和frontbuffer就能把新界面显示出来了。

这一步是在SurfaceFlinger::postFramebuffer()函数中完成的,这个函数最终会使用eglSwapBuffers(...)函数把上一步绘制好的backbuffer和正在显示的frontbuffer交换,之后新的界面就显示在屏幕上了。

而eglSwapBuffers经过一系列步骤,最终会调用gralloc模块中framebuffer_device_t中的post(…)方法交换前后buffer,把最新的界面显示在屏幕上。

SurfaceFlinger叠加各个Surface的过程可以总结如下:首先,把保存有新的界面信息的缓冲区作为每一个Layer的纹理对象;然后,根据每一个Layer的信息和Layer之间的重叠关系,每一个Layer的可见区域;之后,叠加需要更新的Layer,并保存在backbuffer中;最后,交换backbuffer和frontbuffer,新界面就会显示在屏幕上。

四、四、示例程序

为了更清楚的说明Surface和SurfaceFlinger的交互关系和使用方法,下面的附件中附带了一个简单的示例程序,其中,会在屏幕上显示0-9这10个数字,然后退出程序。程序用C++语言实现,其中会使用Surface::lock(…)从SurfaceFlinger锁定并获取一块缓冲区,然后,使用Skia在这块缓冲区中绘制图像,最后使用Surface::unlockAndPost()提交缓冲区并请求SurfaceFlinger重绘界面。

只要把附件中的文件解压并放到android源代码的framework/base/cmds目录下,然后使用mm编译就可得到可执行文件SurfaceFlingerTest,将其放到板子上,然后以root身份执行即可。

surfaceflinger_test.zip

附件:

参考资料

1.Android系统匿名共享内存Ashmem(Anonymous Shared Memory)简要介绍和学习计划

2.Android HAL(硬件抽象层)介绍以及调用

3.Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析

4.Android进程间通信(IPC)机制Binder简要介绍和学习计划

5.ANDROID窗口系统机制之显示机制

6.浅谈Google Skia图形处理引擎

7.OpenGL超级宝典(第4版)[美]Richard S.Wright等张琪付非译人民邮电出版社

Android中绘制常见的几何图形的代码清单(精)

Android中绘制常见的几何图形的代码清单 范美英 (北京信息职业技术学院) 摘要:Android中可以自定义视图,只需要将视图类继承自View,并重写其onDraw方法即可。本文详细罗列了Android应用界面中绘制常见的几何图形的代码清单。 关键词: Android;自定义视图;几何图形 1 src/MainActivity.java类的代码 package com.zyk.geographicviews; import android.app.Activity; import android.os.Bundle; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(https://www.360docs.net/doc/7e14590873.html,yout.activity_main); } } 2 src/Circle.java类的代码 package com.zyk.geographicviews; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Style; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.Toast;

Android应用开发基础习题集

任务一 Android开发环境的搭建 第一部分知识回顾与思考 1.Android的四层架构分别包括哪几层分别起到什么作用 答:Linux内核层(Linux Kernel):基于Linux内核,内核为上层系统提供了系统服务。 系统库层(Libraries):系统库基于C/C++语言实现,通过接口向应用程序框架层提供编程接口。 应用框架层(Application Framework):为开发者提供了一系列的Java API,包括图形用户界面组件View、SQLite数据库相关的API、Service组件等。 应用程序层(Applications):包含了Android平台中各式各样的应用程序。 第二部分职业能力训练 一、单项选择题(下列答案中有一项是正确的,将正确答案填入括号内) 1.Android四层架构中,应用框架层使用的是什么语法( C ) A.C B.C++ C.Java D.Android 2.Android四层架构中,系统库层使用的是什么语法( B ) A.VB B.C /C++ C.Java D.Android 3.应用程序员编写的Android应用程序,主要是调用( B )提供的接口进行实现。 A.应用程序层 B.应用框架层 C.应用视图层 D.系统库层 二、填空题(请在括号内填空) 1.在Android智能终端中,有很多应用如拍照软件、联系人管理软件,它们都属于Android的(应用程序)层。 2.为了让程序员更加方便的运行调试程序,Android提供了(模拟器),可以方便的将程序运行其上,而不要实际的移动终端。 3.为了支持Java程序运行,我们需要安装(JDK)。 三、简答题 1.简述Android开发环境安装的步骤。 答:下载并安装JDK,配置JDK的环境变量; 从Anroid官网上下载Android开发组件(包含Eclipse和Android SDK、ADT); 安装Android开发环境(包括配置Android SDK的环境变量、打开Eclipse通过菜单设定Android SDK 路径)。 2.简述Android应用程序创建和运行的步骤。 答:通过菜单创建Android应用程序,设置应用程序名、Android版本等基本信息。

软件测试用例实例非常详细

1、兼容性测试在大多数生产环境中,客户机工作站、网络连接和数据库服务器的具体硬件驱动程客户机工作站可能会安装不同的软件例如,应用程序、规格会有所不同。序等而且在任何时候,都可能运行许多不同的软件组合,从而占用不同的资源。测试目的 操作系统系统软件外设应用软件结果配置说明 Window2000(S) 服务器 WindowXp Window2000(P) Window2003 TestCase_LinkWorks_WorkEvaluate 用例编号LinkWorks项目名称WorkEvaluate模块模块名称研发中心-质量管理部项目承担部门 用例作者2005-5-27 完成日期质量管理部本文档使用部门评审负责人审核日期 批准日期 注:本文档由测试组提交,审核由测试组负责人签字,由项目负责人批准。 历史版本: 备注起止日期参与者作者状态/版本 V1.1 1.1. 疲劳强度测试用例

强度测试也是性能测试是的一种,实施和执行此类测试的目的是找出因资源不足或资源争用而导致的错误。如果内存或磁盘空间不足,测试对象就可能会表现出一些在正常条件下并不明显的缺陷。而其他缺陷则可能由于争用共享资源(如数据库锁或网络带宽)而造成的。强度测试还可用于确定测试对象能够处理的最大工作量。 测试目的 测试说明 用户并发设置添加10连续运行8前提条件小时,输出/响应输入测试需求/动作是否正常运行1 2小时功能4小时6小时8 小时 2小时功能1 4小时6小时 小时8 一、功能测试用例 此功能测试用例对测试对象的功能测试应侧重于所有可直接追踪到用例或业务功能和业务规则的测试需求。这种测试的目标是核实数据的接受、处理和检索是否正确,以及业务规则的实施是否恰当。主要测试技术方法为用户通过GUI(图形用户界面)与应用程序交互,对交互的输出或接受进行分析,以此来核实需求功能与实现功能是否一致。

软件测试用例模板

软件测试用例模板

用例编号TestCase_LinkWorks_WorkEvaluate 项目名称LinkWorks 模块名称WorkEvaluate模块 项目承担部门信息部 用例作者 完成日期2015-5-27 评审负责人 审核日期 批准日期 注:本文档由测试组提交,审核由测试组负责人签字,由项目负责人批准。历史版本: 版本/状态作者参与者起止日期备注 V1.1 一、功能测试用例 此功能测试用例对测试对象的功能测试应侧重于所有可直接追踪到用例或业务功能和业务规则的测试需求。这种测试的目标是核实数据的接受、处理和检索是否正确,以及业务规则的实施是否恰当。主要测试技术方法为用户通过GUI (图形用户界面)与应用程序交互,对交互的输出或接受进行分析,以此来核实需求功能与实现

功能是否一致。 用例标识LinkWorks_ WorkEvaluate _02 项目 名称 https://www.360docs.net/doc/7e14590873.html, 开发人员模块 名称 WorkEvaluate 用例作者参考 信息 工作考核系统界面设计 (2005_03_28).vsd 测试类型设计 日期 2006-9- 27 测试 人员 测试方法黑盒测试 日期 用例描述前置条件 编号权 限 ( 并 列 测试项测 试 类 别 描述/输入/操 作 期望结果真 实 结 果 备 注

关系) 000 01 无列 表 页 面 导航栏导 航 测 试 浏览\点击导 航连接 详细正确 导航页面 所在位置 000 02 添加删 除修改 按钮 添加修改删 除按钮是否 可用 不可用 000 03 接受、 汇报按 钮 1)不是自 己负责的 数据未考 核之前能 否接受\汇 报 不能 2)属于自 己负责的 未接受之 前时候是 否可以接 受 能

测试用例设计练习

一、等价类划分法 例子1: 现在有一个档案管理系统,容许用户通过输入年月对档案文件进行检索,系统对查询条件年月的输入限定为1990年1月-2049年12月,并规定,日期由6位数字组成,前4位表示年,后2位表示月。 1,根据需求进行分析,找出有哪些输入条件 年份:【1990,2049】 月份:【01,12】 字符长度:6位 字符类型:数字 2,画出等价类 输入条件有效等价类边界值分析无效等价类 年份【1990,2049】(1)上点:1990,2049(12) 离点:1989,2050 内点:2016 <1990 (2)>2049 (3) 月份【01,12】(4)上点:01,12(13) 离点:00,13 内点:11 <01 (5)>12 (6) 字符长度6位(7)上点:6 离点:5,7 内点:6 <6 (8)>6 (9) 字符类型数字(10)非数字(11)3,为每个等价类规定一个唯一编号(如上图) 4,转换成测试用例 转换测试用例的原则: A,设计一个测试用例尽可能多的覆盖多个有效等价类; B,设计一个测试用例必须对应覆盖一个无效等价类。 有效等价类用例: 用例1:201611 (1)(4)(7)(10) 无效等价类用例: 用例2:198911 (2) 用例3:205011 (3) 用例4:201600 (5) 用例5:201613 (6) 用例6:20161 (8) 用例7:2016113 (9) 用例8:20161a/abcedf (11) 根据边界值分析法分析后补充测试用例 用例9:199001 (12) 用例10:204912 (13) 5,转成正式格式用例(用例写作的8大要素) 用例编号D1223232_ST_Search_Date_001 项目搜索功能 标题输入正确的日期格式成功搜索

测试用例实例

测试用例实例 Corporation standardization office #QS8QHH-HHGX8Q8-GNHHJ8

测试用例实例 1、一个好的用例的表述要点,即用例中应当包含的信息 一个优秀的用例,应该包含以下信息: 1)软件或项目的名称 2)软件或项目的版本(内部版本号) 3)功能模块名 4)测试用例的简单描述,即该用例执行的目的或方法 5)测试用例的参考信息(便于跟踪和参考) 6)本测试用例与测试用例间的依赖关系 7)本用例的前置条件,即执行本用例必须要满足的条件,如对的访问权限 8)用例的编号(ID),如可以是软件名称简写-功能块简写-NO.。 9)步骤号、操作步骤描述、测试数据描述 10) 预期结果(这是最重要的)和实际结果(如果有BUG管理工具,这条可以省略)11)开发人员(必须有)和测试人员(可有可无) 12)测试执行日期 2、 该测试案例是以一个B/S结构的登录功能点位被测对象,该测试用例为黑盒测试用例。假设用户使用的浏览器为IE6.0 SP4。 功能描述如下: 1.用户在地址栏输入相应地址,要求显示登录界面; 2.输入用户名和密码,登录,系统自动校验,并给出相应提示信息; 3.如果用户名或者密码任一信息未输入,登录后系统给出相应提示信息; 4.连续3次未通过验证时,自动关闭IE。

取款用例说明: 此用例完成用户利用自动取款机取款的全部流程,分为以下流程:插卡,输入密码,选择金额,取款,取卡等操作。 事件流: 该用例在用户插卡之后启动 1. 系统提示用户插卡; 2. 提示客户输入密码信息; 3. 密码输入完毕后,客户选择“确认”,向系统提交信息;

Android应用开发基础习题

-- 任务一Android 开发环境的搭建 第一部分知识回顾与思考 1.Android 的四层架构分别包括哪几层?分别起到什么作用? 答:Linux 内核层(Linux Kernel ):基于Linux 内核,内核为上层系统提供了系统服务。 系统库层(Libraries ):系统库基于C/C++ 语言实现,通过接口向应用程序框架层提供编程接口。 应用框架层(Application Framework ):为开发者提供了一系列的Java API,包括图形用户界面组件

View 、SQLite 数据库相关的API 、Service 组件等。 应用程序层(Applications ):包含了Android 平台中各式各样的应用程序。 第二部分职业能力训练 一、单项选择题(下列答案中有一项是正确的,将正确答案填入括号内) 1.Android 四层架构中,应用框架层使用的是什么语法?(C)A .CB .C++C.Java D.Android 2.Android 四层架构中,系统库层使用的是什么语法?(B)A .VBB.C /C++C.Java D .Android 3.应用程序员编写的Android 应用程序,主要是调用(B)提供的接口进行实现。 A .应用程序层DCB.应用框架层.应用视图层.系统库层

二、填空题(请在括号内填空) 1.在Android 智能终端中,有很多应用如拍照软件、联系人管理软件,它们都属于Android 的(应用程 序)层。 2.为了让程序员更加方便的运行调试程序,Android 提供了(模拟器),可以方便的将程序运行其上, 而不要实际的移动终端。 程序运行,我们需要安装(Java 3.为了支持)。JDK 三、简答题 1.简述Android 开发环境安装的步骤。 答:下载并安装JDK ,配置JDK 的环境变量; 从Anroid 官网上下载Android 开发组件(包含Eclipse 和

软件测试用例实例 非常详细

1、兼容性测试 在大多数生产环境中,客户机工作站、网络连接和数据库服务器的具体硬件规格会有所不同。客户机工作站可能会安装不同的软件例如,应用程序、驱动程序等而且在任何时候,都可能运行许多不同的软件组合,从而占用不同的资源。 测试目的 配置说明操作系统系统软件外设应用软件结果 服务器Window2000(S) WindowXp Window2000(P) Window2003 用例编号TestCase_LinkWorks_WorkEvaluate 项目名称LinkWorks 模块名称WorkEvaluate模块 项目承担部门研发中心-质量管理部 用例作者 完成日期2005-5-27 本文档使用部门质量管理部 评审负责人 审核日期 批准日期 注:本文档由测试组提交,审核由测试组负责人签字,由项目负责人批准。历史版本: 版本/状态作者参与者起止日期备注 V1.1

1.1. 疲劳强度测试用例 强度测试也是性能测试是的一种,实施和执行此类测试的目的是找出因资源不足或资源争用而导致的错误。如果内存或磁盘空间不足,测试对象就可能会表现出一些在正常条件下并不明显的缺陷。而其他缺陷则可能由于争用共享资源(如数据库锁或网络带宽)而造成的。强度测试还可用于确定测试对象能够处理的最大工作量。 测试目的 测试说明 前提条件连续运行8小时,设置添加10用户并发 功能1 2小时 4小时 6小时 8小时 功能1 2小时 4小时 6小时 8小时 一、功能测试用例 此功能测试用例对测试对象的功能测试应侧重于所有可直接追踪到用例或业务功能和业务规则的测试需求。这种测试的目标是核实数据的接受、处理和检索是否正确,以及业务规则的实施是否恰当。主要测试技术方法为用户通过GUI(图形用户界面)与应用程序交互,对

Android开发技术期末考试复习题

试题 一、选择题 1 android虚拟设备的缩写是(A VD) 2 Android SDK目前支持的操作系统(Linux) 3 Android开发工具插件(ADT)没有提供的开发功能(自动更新) 4 Android SDK提供一些开发工具可以把应用软件打包成Android格式文件(APK) 5 Android当中基本的所有的UI都是由(view)或者其子类实现的 7下列不是Activity的生命周期方法之一的是() onCreate onStart onRestart onResume onPause onStop onDestroy 8 以下可以做EditText编辑框的提示信息是(adroid:hint) 以下不是手机操作系统的是(windows vista) 下列哪个属性是专用于相对布局的(D) A.android.orientation 线性vertical 垂直horizontal B.android:stretchColumns C.android:layout_alignParentRight D.android:layout_toRightOf 定义LinearLayout垂直方向布局时设置的属性( D ) A.android:layout_height B.android:gravity C.android:layout D. android:orientation vertical 垂直 为了使android适应不同分辨率的机型,布局时字体单位应用( D ) A.dp B.dip 像素 C.px D.sp 下面属于android的动画分类的有( AB) A.Tween B.Frame C.Draw D.Animation Property Animation属性动画android 关于service生命周期的onCreate()和onStart()说法正确的是( AD ) A.当第一次启动的时候先后调用onCreate()和onStart()方法 B.当第一次启动的时候只会调用onCreate()方法 C.如果service已经启动,将先后调用onCreate()和onStart()方法 D.如果service已经启动,只会执行onStart()方法,不在执行onCreate()方法 在android中使用Menu时可能需要重写的方法有(AC) A、onCreateOptionsMenu() 三种菜单:选项菜单、上下文菜单、子菜单 B、onCreateMenu() C、onOptionsItemSelected() D、onItemSelected() Intent传递数据时,下列的数据类型哪些可以被传递(ABCD) A、Serializable B、charsequence C、Parcelable D、Bundle java.io包中的( A )和( B )类主要用于对对象Object的读写。 A. objectInputStream B. objectOutPutStream C.Reader D.writer 继承ContentProvider需要实现(ABCD)等方法。 A. insert B. delete C. update D. query

常见的测试用例设计方法都有哪些

常见的测试用例设计方法都有哪些 常见的测试用例设计方法都有哪些? 请分别以具体的例子来说明这些方 法在测试用例设计工作中的应用。 1. 等价类划分常见的软件测试面试题划分等价类: 等价类是指某个输入域的子集合.在该子集合中,各个输入数据对于揭露程序中的错误都是等效的.并 合理地假定:测试某等价类的代表值就等于对这一类其它值的测试.因此,可以把全部输入数据合理划分为若干等价类,在每一个等价类中取一个数据作为测试的输入条件,就可以用少量代表性的测试数据.取得较好的测试结果.等价类划分可有两种不同的情况:有效等价类和无效等价类. 2. 边界值分析法边界值分析方法是对等价类划 分方法的补充。测试工作经验告诉我,大量的错误是发生在输入或输出范围的边界上,而不是发生在输入

输出范围的内部.因此针对各种边界情况设计测试用例,可以查出更多的错误. 使用边界值分析方法设计测试用例,首先应确定边界情况.通常输入和输出等价类的边界,就是应着重测试的边界情况.应当选取正好等于,刚刚大于或刚刚小于边界的值作为测试数据,而不是选取等价类中的典型值或任意值作为测试数据. 3. 错误推测法基于经验和直觉推测程序中所有可能存在的各种错误, 从而有针对性的设计测试用例的方法. 错误推测方法的基本思想: 列举出程序中所有可能有的错误和容易发生错误的特殊情况根据他们选择测试用例. 例如, 在单元测试时曾列出的许多在模块中常见的错误. 以前产品测试中曾经发现的错误等, 这些就是经验的总结。还有, 输入数据和输出数据为0 的情况。输入表格为空格或输入表格只有一行. 这些都是容易发生错误的情况。可选择这些情况下的例子作为测试用例. 4. 因果图方法前面介绍的等价类划分方法和边界值分析方法,都是着重考虑输入条件,但未考虑输入条件之间的联系, 相互组合等. 考虑输入条件之间的相互组合,可能会产生一些新的情况. 但要检查

软件测试-测试报告模板

XX测试报告模版适用于XX公司 编写者: XX 文档编号: 编写日期: 2010-11-25

分发列表 文档修订历史 [模板修订历史 (文档首次使用前请删除)]

目录 1.测试概述 (4) 1.1.测试项目简述 (4) 1.2.名词定义 (4) 1.3.参考文档 (4) 2.测试环境与配置 (4) 3.测试情况 (4) 3.1.测试版本情况 (4) 3.2.测试用例统计执行情况 (4) 3.3.测试组织 (4) 4.测试结果及分析 (5) 4.1.测试情况统计分析 (5) 4.2.覆盖分析 (5) 4.2.1.需求覆盖 (5) 4.2.2.测试覆盖 (5) 4.3.缺陷的统计与分析 (5) 4.3.1.缺陷汇总 (5) 4.3.2.缺陷分析 (5) 4.4.测试质量对比统计 (5) 5.遗留缺陷与未解决问题 (5) 6.测试总结及风险分析 (6) 7.测试报告批准 (6)

1. 测试概述 1.1. 测试项目简述 <大、小、临时版本确定,测试范围 1. 测试需求 那些新增的需求验证 那些变更需求的需求验证 本次版本中可验证的需求列表 2. 修改问题的测试 3. 其他的功能测试内容> 1.2. 名词定义 本轮验证测试过程中涉及到需求、更新的产品术语、新产品术语等。 1.3. 参考文档 <参考的需求分档、设计文档等> 2. 测试环境与配置 简要介绍测试环境及其配置。 3. 测试情况 3.1. 测试版本情况 测试版本版本号,是否接受该版本以及原因表述。 什么时候接收的版本,什么时间版本部署完成 测试过程中有无更新版本 更新版本对测试的影响 测试中冒烟测试是否通过 3.2. 测试用例统计执行情况 3.3. 测试组织

手机软件系统测试用例设计举例

一、等价类分析法 等价类划分方法针对手机状态大致可以归几个大类: 1.按键类(等价法): 有效输入和无效输入(有效输入指UM和菜单指示;无效输入指测试菜单功能此时没有定义的按键和用户动作); 2.外部中断类(等价法): 常用、不常用及无效 2. 1."常用: 来电和来消息(短信、彩信、push消息);掀合盖;侧键;耳机&FM;情景模式;电量不足 2. 2."不常用: 充电;闹钟&记事本&关机时间&整点报时提示;Icon&动画显示;Icon&动画刷新;编辑界面&pop显示框输入为空或满;编辑界面&pop显示框状态输入法默认&字符编码默认;失效SIM卡;大容量等SIM卡兼容;排序;号码识别; 2. 3."无效: “资料读取中…”;“复制中…”;“请稍后再试” 3.存储器类 3.

1."等价法分类: 读或写;不读或不写。 3. 2."因果法分类: 先SIM卡后手机;先手机后SIM卡;提示用户选择存储器(对比Nokia)。 3. 3."操作分类: 读;写;新增;删除;复制(先删除后新增;先新增后删除) 4.状态类: 正确;错误;变更;用户设定变更 举例一,短消息发送功能: 英文: Default 7-bit alphabet (over 160 characters) 合法等价类:0~160 非法等价类: :>160 The quick fox jumps over the lazy brown dog 中文: UCS-2 alphabet (over 70 characters) 合法等价类:0~70 非法等价类:

诺基亚(英文): Extended default 7-bit alphabet (over 140 Bytes),智慧短信,可以携带黑白图片。 合法等价类:0~140 非法等价类: :>140 在写字板里面输入“联通”二字,保存后,再打开,即出现乱码。 举例二,单个通话实例的拨打与挂断 测试用例标识 测试阶段: 系统测试 测试项 单个通话实例的拨打与挂断 测试项属性A参照规范 重要级别高测试原因 手机在待机状态下,确保手机能正常拨出电话 预置条件 1.正常信号环境 2.IDLE状态 3.默认原厂参数设定

Android开发轻松实现带文字的图片按钮

Android开发轻松实现带文字的ImageButton 实际上,ImageButton是不能添加文字的。要实现带文字的ImageButton的方法很多,这里仅列举一种方法:自定义一个继承自ImageButton的类,然后Override它的onDraw(Canvas canvas)方法。具体步骤如下: 1)新建一个Android工程,例如工程名:TestImageButton。怎么建工程?不用我多说了吧。 2)新建一个MyImageButton类,继承android.widget.ImageButton 3)为类MyImageButton添加成员函数,详细代码如下: package https://www.360docs.net/doc/7e14590873.html,; import android.content.Context; import android.graphics.Canvas;

import android.graphics.Paint; import android.util.AttributeSet; import android.widget.ImageButton; public class MyImageButton extends ImageButton { public String text = null; //要显示的文字 public float textX,textY; //文本显示的坐标位置 public int color; //文字的颜色 public MyImageButton(Context context, AttributeSet attrs) { super(context,attrs); textX=20; textY=60; } //设置需要显示的文本 public void setText(String text){ this.text = text; //设置文字 } //设置文本显示的颜色 public void setColor(int color){ this.color = color; //设置文字颜色 } // 设置显示文本的X、Y坐标 public void setPosition(float XX,float YY){ t extX = XX; t extY = YY; } @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); Paint paint=new Paint(); paint.setTextAlign(Paint.Align.CENTER); paint.setColor(color); canvas.drawText(text, textX, textY, paint); //绘制文字} } 4)在布局文件中引用:

系统测试用例模板

XX项目 系统测试用例说明书

目录 1引言 ........................................................ 1.1编写目的............................................... 1.2背景................................................... 1.3定义................................................... 1.4参考资料............................................... 2功能测试用例................................................. 2.3管理员测试用例......................................... 2.3.1 被测特性........................................ 2.3.2 A1.1添加用户测试用例........................... 测试需求............................................... A1.1.1.................................................

1引言 1.1编写目的 本文档为(在此指出软件名称)的系统测试活动提供范围、方法、资源和进度方面的指导。预期的读者范围包括: ●项目经理 ●测试人员 ●用户 1.2背景 说明: (1)测试计划所从属的软件系统的名称; (2)该开发项目的历史,列出用户和执行此项目测试的计算中心,说明在开始执行本测试计划之前必须完成的各项工作。 1.3定义 1.4参考资料

第四章 Android游戏开发之图形界面

第四章 Android游戏开发之图形界面 4.1 图片 图片是游戏的必备元素之一。 4.1.1 drawable对象 游戏所使用到的图片资源,我们都把它放置到res文件夹中的drawable中,当增加了drawable对象后,Android SDK会为该图片 资源在R清单文件中创建一个索引项,该索引的名字为 R.drawable.fileName。 生成了该资源的索引后,在XML资源文件中就可以通过@drawable/fileName来访问该图片资源,也可以在代码中 R.drawable.fileName来访问该drawable对象。而 R.drawable.fileName只是一个int类型的常量,它只是代表了 drawable对象的ID,程序代码当中需要获取到实际的drawable对象, 需要调用Resource的getDrawable(int id)方法来获取。 4.1.2 Bitmap Bitmap即位图,Bitmap类中欧那个提供了一些静态方法来创建新的Bitmap对象,如下是常用的方法。

对象,如:BitmapDrawable drawable = new BitmapDrawable(bitmap);获取BitmapDrawable所包装的Bitmap对象可以调用该类的getBitmap()方法,如Bitmap bitmap = drawable.getBitmap();。 BitmapFactory是一个Bitamap的工具类,它共提供了多种方法以便于从不同的数据源来解析和创建Bitmap对象,如下。

drawable目录中,而程序代码中通过该图片对应的资源ID来获取封装该图片的drawable对象即可。但手机系统的内存是有限的,如果不停的创建Bitmap对象,就会导致内存不够用的情况,所以Bitmap有各两个非常重要的方法来判断图片资源的是否回收和强制Bitmap进行回收。一下都是一些Bitmap常用到的方法。

Android-客户端开发流程图及案例

Android 客户端开发流程1项目流程图 A A A A A A A A A

2项目阶段描述2.1 项目需求分析阶段描述 输入: 《项目产品开发计划书》 《总体方案书》 输出: 《项目产品需求规格说明书》 《产品测试计划及裁减说明书》 2.2 项目设计施阶段 输入: 《项目产品需求规格说明书》 《产品测试计划及裁减说明书》 输出: 《产品概要设计说明书》 《系统测试方案》 《集成测试方案》 2.3 项目实施阶段 输入: 《项目产品需求规格说明书》 《产品概要设计说明书》 待更新的《系统测试方案》 待更新的《集成测试方案》 输出: 《产品详细设计说明书》 更新的《系统测试方案》 更新的《集成测试方案》

2.4 项目测试阶段 输入: 《项目产品需求规格说明书》 《产品详细设计说明书》 《系统测试方案》 《集成测试方案》 《产品单元测试记录》 输出: 《系统测试缺陷记录》 《产品单元测试报告》 《集成测试报告》 《系统测试报告》 2.5 项目验收阶段 输入: 《项目产品需求规格说明书》 《产品详细设计说明书》 《系统测试缺陷记录》 《产品单元测试报告》 《集成测试报告》 《系统测试报告》 输出: 《项目总结报告》 《项目中无法满足功能项说明书》 《维护方案》

本文介绍了如何使用Android搭建客户端,实现手机和服务器的交互。让我们了解如何采用SSH框架,把服务器端的信息用JSON的形式发送到手机端。 AD:笔者以前是学的Java EE,由于项目需要要开发Android,所以临时补了一个多星期,主要是手机端和服务器端交互,双向开发的。 首先在服务器端,我采用的是SSH框架,struts 2集合了JSON插件,服务器和客户端的信息交互采用的JSON 来传输,由于在服务器端用了Struts 2,所以我就用装了一个JSON插件。这样,很轻易的就把服务器端的信息用JSON的形式发送到了手机端。以下是代码: 首先,在服务器端搭建好SSH框架,具体细节就不在陈述。struts.xml配置如下: 1. 2. 3.result 4. 5. 6. 7. 8. 9. result 10. 11. 手机端的代码如下: 首先,手机端有一个缓存类,主要用于缓存一些手机端需要访问的数据,这样的好处是可以达达节省手机和服务器的交互,用单例实现的: 1.packagecom.jclick.cache; 2. https://www.360docs.net/doc/7e14590873.html,er; 4. 5.publicclassCache{ 6. 7.privateUserUser; 8. 9.privateCache(){ 10. 11.} 12./**构造单例*/ 13.privatestaticclassCacheHolder{ 14.privatestaticfinalCacheINSTANCE=newCache(); 15.} 16.publicCachegetInstance(){ 17.returnCacheHolder.INSTANCE;

测试用例实例

测试用例实例 1、一个好的用例的表述要点,即用例中应当包含的信息 一个优秀的测试用例,应该包含以下信息: 1)?软件或项目的名称 2)?软件或项目的版本(内部版本号) 3)?功能模块名 4)?测试用例的简单描述,即该用例执行的目的或方法 5)?测试用例的参考信息(便于跟踪和参考) 6)?本测试用例与其他测试用例间的依赖关系 7)?本用例的前置条件,即执行本用例必须要满足的条件,如对数据库的访问权限 8)?用例的编号(ID),如可以是软件名称简写-功能块简写-NO.。 9)?步骤号、操作步骤描述、测试数据描述 10) 预期结果(这是最重要的)和实际结果(如果有BUG管理工具,这条可以省略) 11)开发人员(必须有)和测试人员(可有可无) 12)测试执行日期 2、实例 该测试案例是以一个B/S结构的登录功能点位被测对象,该测试用例为黑盒测试用例。假设用户使用的浏览器为 SP4。 功能描述如下: 1.用户在地址栏输入相应地址,要求显示登录界面; 2.输入用户名和密码,登录,系统自动校验,并给出相应提示信息; 3.如果用户名或者密码任一信息未输入,登录后系统给出相应提示信息; 4.连续3次未通过验证时,自动关闭IE。 表4-1登录界面测试用例

自动取款机取款用例规约和测试用例 取款用例说明: 此用例完成用户利用自动取款机取款的全部流程,分为以下流程:插卡,输入密码,选择金额,取款,取卡等操作。 事件流: 该用例在用户插卡之后启动 1. 系统提示用户插卡; 2. 提示客户输入密码信息; 3. 密码输入完毕后,客户选择“确认”,向系统提交信息; 4. 系统验证客户输入的密码信息,确认正确后,进入选择系统主界面; 5. 用户选择取款选项; 6. 系统进入取款金额界面并提示用户输入金额; 7. 系统验证可以取款并输出钱款; 8. 系统提示用户取卡,操作完成。 基本流: 用户取款。 备选流: 1.用户密码错误 2.取款金额不符合要求。 前置条件: 用户必须插入正确的银行卡才能开始执行用例。 后置条件: 如果系统确认用户信息正确,成功登陆,则系统启动主界面,等待用户发送消息,进行查询和取款等操作。

Android应用开发基础习题集

任务一 Android开发环境得搭建 第一部分知识回顾与思考 1.Android得四层架构分别包括哪几层?分别起到什么作用? 答:Linux内核层(Linux Kernel):基于Linux内核,内核为上层系统提供了系统服务。 系统库层(Libraries):系统库基于C/C++语言实现,通过接口向应用程序框架层提供编程接口。 应用框架层(Application Framework):为开发者提供了一系列得Java API,包括图形用户界面组件View、SQLite数据库相关得API、Service组件等。 应用程序层(Applications):包含了Android平台中各式各样得应用程序。 第二部分职业能力训练 一、单项选择题(下列答案中有一项就是正确得,将正确答案填入括号内)1.Android四层架构中,应用框架层使用得就是什么语法?( C ) A.C B.C++ C.Java D.Android 2.Android四层架构中,系统库层使用得就是什么语法?( B ) A.VB B.C /C++ C.Java D.Android 3.应用程序员编写得Android应用程序,主要就是调用( B )提供得接口进行实现。 A.应用程序层 B.应用框架层 C.应用视图层 D.系统库层 二、填空题(请在括号内填空) 1.在Android智能终端中,有很多应用如拍照软件、联系人管理软件,它们都属于Android得(应用程序)层。 2.为了让程序员更加方便得运行调试程序,Android提供了(模拟器),可以方便得将程序运行其上,而不要实际得移动终端。 3.为了支持Java程序运行,我们需要安装(JDK)。 三、简答题 1.简述Android开发环境安装得步骤。 答:下载并安装JDK,配置JDK得环境变量; 从Anroid官网上下载Android开发组件(包含Eclipse与Android SDK、ADT); 安装Android开发环境(包括配置Android SDK得环境变量、打开Eclipse通过菜单设定Android SDK 路径)。

软件测试用例设计案例

软件测试用例设计案例 等价类型划分法等价类划分是一种典型的黑盒测试方法用这一方法设计测试用例完全不考虑程序的内部结构只根据对程序的需求和说明即需求规格说明书。 由于穷举测试工作量太大以至于无法实际完成促使我们在大量的可能数据中选取其中的一部分作为测试用例。 例如在不了解等价分配技术的前提下我们做计算器程序的加法测试时测试了11121314之后还有必须测试15和16吗能否放心的认为它们时正确的我们感觉15和16与前面的1112都是类似的简单加法。 等价类划分法是把程序的输入域划分成若干部分然后从每个部分中选取少数代表性数据当作测试用例。每一类的代表性数据在测试中的作用等价于这一类中的其他值也就是说如果某一类中的一个例子发现了错误这一等价类中的其他例子也能发现同样的错误反之如果某一类中的一个例子没有发现错误则这一类中的其他例子也不会查出错误。使用这一方法设计测试用例首先必须在分析需求规格说明的基础上划分等价类列出等价类表。 1.划分等价类和列出等价类表。 等价类是指某个输入域的子集合。在该子集合中各个输入数据对于揭露程序中的错误都是等效的。并合理地假定测试某等价类的代表值就等于对这一类其他值的测试。 因此可以把全部输入数据合理划分为若干等价类在每一个等价类中取一个数据作为测试的输入条件就可以用少量代表性的测试数据取得较好的测试结果。等价类划分有两种不同的情况有效等价类和无效等价类。 有效等价类是指对于程序的规格说明来说是合理的、有意义的输入数据构成的集合。利用有效等价类可检验程序是否实现了规格说明中所规定的功能和性能。 无效等价类与有效等价类的定义恰巧相反。 设计测试用例时要同时考虑这两种等价类。因为软件不仅要能接收合理的数据也要能经受意外的考验。这样的测试才能确保软件具有更高的可靠性。 下面给出6条确定等价类的原则①在输入条件规定了取值范围或值的个数的情况下则可以确立一个有效等价类和两个无效等价类。 ②在输入条件规定了输入值的集合或者规定了“必须如何”的条件的情况下可以确立一个有效等价类和一个无效等价类。 ③在输入条件是一个布尔量的情况下可确定一个有效等价类和一个无效等价类。 ④在规定了输入数据的一组值假定n个并且程序要对每一个输入值分别处理的情况下可确立n个有效等价类和一个无效等价类。 软件工程规范、实践与案例分析2⑤在规定了输入数据必须遵守的规则的情况下可确立一个有效等价类符合规则和若干个无效等价类从不同角度违反规则。 ⑥在确知已划分的等价类中各元素在程序处理中的方式不同的情况下则应再将该等价类进一步地划分为更小的等价类。 在确立了等价类之后建立等价类表列出所有划分出的等价类如表5-1。 表5-1等价类表示例输入条件有效等价类无效等价类............. 2.确定 测试用例根据已列出的等价类表按以下步骤确定测试用例①为每个等价类规定一个唯一的编号②设计一个新的测试用例使其尽可能多地覆盖尚未覆盖的有效等价类。重复这一步最后使得所有有效等价类均被测试用例所覆盖③设计一个新的测试用例使其只

Android绘图机制(二)——自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解资料

Android绘图机制(二)——自定义View 绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解 我们要想画好一些炫酷的View,首先我们得知道怎么去画一些基础的图案,比如矩形,圆形,三角形,多边形等…. 新建一个项目 然后我们创建一个listview,每个图案一个Activity,这样看起来是不是很顺眼 编写ListView private ListView listview; //item上的数据源 private String[] name = {"矩形", "圆形", "三角形", "扇形", "椭圆", "曲线","文字和图片"}; //listview的adapter private ArrayAdapteradapter; private void initView() { //实例化listview listview = (ListView) findViewById(R.id.listview); //实例化数据源 adapter = new ArrayAdapter(this, https://www.360docs.net/doc/7e14590873.html,yout.simple_list_item_1, name); //listview设置adapter listview.setAdapter(adapter); //listview设置点击事件 listview.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) {

相关文档
最新文档