- Android板级支持与硬件相关子系统
- 韩超等
- 3657字
- 2020-08-28 12:21:34
4.2 显示子系统结构
↘4.2.1 总体结构
Android显示结构的结构在Android1.x版本和Android2.x及之后版本的下层实现有所区别。Android 1.x版本的显示系统没有独立的硬件抽象层,而是在libui库中直接调用Framebuffer驱动程序。Android2.x的主要变化是增加了名为gralloc的硬件模块作为显示系统的硬件抽象层。gralloc的原本含义是图形设备的分配。
在Android2.x及之后的版本中,显示系统的结构如图4-1所示。
图4-1 显示系统的结构
Android的显示系统自下而上,包括以下几个部分的内容。
(1)驱动程序
显示系统通常使用Framebuffer作为驱动程序,也可以使用变化的Framebuffer设备驱动,或者结合其他驱动程序使用。
(2)硬件抽象层
显示系统的硬件抽象层gralloc模块是一个标准的硬件模块,其头文件的路径为:hardware/libhardware/include/hardware/gralloc.h。gralloc模块是放置于/system/lib/hw中的动态库,名称为gralloc.<hardware>.so。
(3)本地框架层
本地框架层中的UI库和Surface系统均和显示部分相关,其中也包含了显示基本系统和相关部分联系。
UI库的头文件路径为:frameworks/base/include/ui/。UI库源代码路径:frameworks/base/libs/ui/。
·frameworks/base/include/surfaceflinger/:SurfaceFlingerClient的头文件。
·frameworks/base/libs/surfaceflinger_client/:libsurfaceflinger_client库的源代码。
·frameworks/base/services/surfaceflinger/:SurfaceFlinger的实现。
(4)JNI部分
提供Surface的给Java层的作为接口。
·frameworks/base/core/jni/android_view_Surface.cpp:Surface的JNI的代码。
(5)Java层的Surface等类
·frameworks/base/core/java/android/view/:包括图层几个相关的类。
其中主要为android.view中的Surface和View类,前者是图层在Java层中的反映,后者是所有控件的基类。另有一个SurfaceView类,可以用于上层的直接图层操作。
提示:Android 4.2的UI库和SurfaceFlinger的内容在frameworks/native/目录中。
↘4.2.2 核心结构和UI库
1.基本结构的定义
在Android 2.3及之后的版本中,由于增加了对NDK中的本地应用“访问本地窗口”的支持,因此显示方面部分的数据结构也被重新进行了定义。
显示相关的结构包含在框架层的几个头文件中。
·framework/base/include/ui/android_native_buffer.h:定义用于显示的内存接口。
·framework/base/native/include/android/native_window.h:定义窗口。
几个文件的内容被框架层使用,也被基于NDK的应用作为头文件使用。
android_native_buffer_t表示显示内存区域,此结构的信息为宽、高、每行数目(stride)、格式和内存区域的指针。android_native_window_t表示一个Android框架层中的窗口,由ANativeWindow定义得到,其中的几个函数指针为窗口的操作,如下所示。
·setSwapInterval:交换内存。
·dequeueBuffer:把内存从队列取出,如果没有内存将阻塞。
·lockBuffer:锁住内存,锁住后才能修改这块内存。
·queueBuffer:发送内存,将其解锁并发送显示。
·query:查询内存的状态。
·perform:执行其他的操作(可以自定义的)。
·cancelBuffer:取消从队列取出内存的操作。
由此可见,Android系统中基本的窗口是一个具有双缓冲区、轮流显示的窗口。对于Android框架中窗口的实现,就是实现android_native_window_t结构(也就是ANativeWindow)。
提示:此处以字母A开头的内容,来自Android 2.3版本开始为NDK的定义。
2.UI库
UI库(libui)在Android显示系统的作用是承上启下的,主要功能是:调用作为硬件抽象层的gralloc模块,对上提供框架层窗口的实现。
其中的几个与显示相关的头文件和源代码文件如下所示。
·FramebufferNativeWindow.*:直接调用gralloc模块,并初始化。
·GraphicBufferAllocator.*:完成显存的分配。
·GraphicBufferMapper.*:完成显存的映射。
·GraphicBuffer.*:表示显存。
FramebufferNativeWindow类本身是继承ANativeWindow(相当于继承了android_native_window_t),表示一个Android中的本地窗口。
FramebufferNativeWindow的构造函数的主体内容如下所示:
FramebufferNativeWindow::FramebufferNativeWindow() : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false) { hw_module_t const* module; if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0)//打开gralloc模块 { int stride; int err; err = framebuffer_open(module, &fbDev); // 打开Framebuffer设备 err = gralloc_open(module, &grDev); // 打开gralloc设备 if (!fbDev || !grDev) return; // 有错误,则返回 mUpdateOnDemand = (fbDev->setUpdateRect != 0); // 可选的setUpdateRect // 初始化FIFO,实际上就是一个双缓冲内存 mNumBuffers = 2; // 双缓冲:有2块内存 mNumFreeBuffers = 2; mBufferHead = mNumBuffers-l; // 初始化2个缓冲区 buffers[0] = new NativeBuffer( fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB); buffers[l] = new NativeBuffer( fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB); // 从gralloc设备中分配内存 err = grDev->alloc(grDev, fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB, &buffers[0]->handle, &buffers[0]->stride); err = grDev->alloc(grDev, fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB, &buffers[l]->handle, &buffers[l]->stride); // 从framebuffer设备中获得常量 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 { LOGE("Couldn't get gralloc module"); } ANativeWindow::setSwapInterval = setSwapInterval; // 为表示窗口的成员赋值 ANativeWindow::dequeueBuffer = dequeueBuffer; ANativeWindow::lockBuffer = lockBuffer; ANativeWindow::queueBuffer = queueBuffer; ANativeWindow::query = query; ANativeWindow::perform = perform; }
FramebufferNativeWindow初始化过程主要的内容分成以下几个步骤。
打开gralloc模块,并打开framebuffer_device_t和alloc_device_t这两个设备。
从framebuffer_device_t设备中获得显示区的宽和高颜色格式,使用它们建立表示内存的NativeBuffer结构。
从alloc_device_t设备中分配内存到NativeBuffer的句柄中。
获得framebuffer_device_t设备中的其他信息。
赋值setSwapInterval、queueBuffer、dequeueBuffer和query等函数指针。
FramebufferNativeWindow类中setSwapInterval、queueBuffer和query等几个函数的实现和framebuffer_device_t有密切的关系。FramebufferNativeWindow实际上是对gralloc模块的一层封装,向Android的本地代码层提供表示窗口的android_native_window_t结构(ANativeWindow)。
GraphicBufferAllocator.类用于显示缓冲的分配,它也打开了Galloc模块,并调用了其中的alloc_device_t设备,其主要的内容如下所示:
status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format, int usage, buffer_handle_t* handle, int32_t* stride) { if (!w || !h) w = h = l; // 对输入的宽高进行保护,最小取值为l status_t err; if (usage & GRALLOC_USAGE_HW_MASK) { err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride); } else { err = sw_gralloc_handle_t::alloc(w, h, format, usage, handle, stride); } // 省略部分内容 return err; }
此处使用mAllocDev的类型为gralloc接口中定义的alloc_device_t,当调用者的参数具有GRALLOC_USAGE_HW_MASK标志的时候,由alloc_device_t调用分配一个内存,否则从软件分配一个内存。
GraphicBufferMapper类用于显示缓冲的映射,其中调用Galloc模块,在其中注册了表示显示缓冲区的内存:
status_t GraphicBufferMapper::registerBuffer(buffer_handle_t handle) { status_t err; if (sw_gralloc_handle_t::validate(handle) < 0) { err = mAllocMod->registerBuffer(mAllocMod, handle); } else { err = sw_gralloc_handle_t::registerBuffer((sw_gralloc_handle_t*)handle); } return err; }
mAllocMod的类型为gralloc_module_t,根据句柄的有效情况,可以从gralloc模块中注册Buffer,也可以从软件注册Buffer。
GraphicBuffer类继承实现了android_native_buffer_t,因此它表示的是显存。在实现中类又调用了分配器GraphicBufferAllocator和映射器GraphicBufferMapper。
↘4.2.3 Surface本地部分
Surface中显示相关的部分实际上是UI库中显示内容的进一步使用,也就是利用显示的设备构建“图层”。
SurfaceFlinger部分的客户端SurfaceFlingerClient和实现部分SurfaceFlinger采取Binder IPC的跨进程通信方式。其中SurfaceFlinger运行于独立的进程或者运行于Java的服务进程(system_server),而调用者通常运行于应用程序的进程。
1.SurfaceFlinger库的与显示相关接口
SurfaceFlingerClient的头文件中使用GraphicBuffer等结构。ISurface.h中具有如下方式的定义:
class ISurface : public IInterface { virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0; virtual status_t setBufferCount(int bufferCount) = 0; }
ISurface类实际上是一个基于Binder的接口,需要下层去实现。Surface.h中定义的Surface类使用ISurface类。
表示显示内存的类在经过多层的封装和实现后,上层能看到的主要就是Surface。
2.SurfaceFlinger库的实现
在图层管理库的SurfaceFlinger中,Layer、LayerBuffer、LayerDim和LayerBlur几个类均表示“图层”,它们实现不同图层的操作。
Layer表示一个普通的图层,其中的嵌套类SurfaceLayerBuffer实际上就是ISurface的实现者。还有显存管理器(BufferManager),它的实现是以双显示缓冲的形式对GraphicBuffer进行管理。
LayerBuffer对gralloc模块也有调用,LayerBuffer类表示一个可以用于“推送(push)”的显存图层。LayerBuffer的嵌套类SurfaceLayerBuffer也是ISurface的实现者。
LayerBuffer嵌套定义的另一个类为Buffer,其构造函数如下所示:
LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, ssize_t offset, size_t bufferSize) : mBufferHeap(buffers), mSupportsCopybit(false) { NativeBuffer& src(mNativeBuffer); src.crop.l = 0; // 剪切区域 src.crop.t = 0; src.crop.r = buffers.w; src.crop.b = buffers.h; src.img.w = buffers.hor_stride ?: buffers.w; // 区域大小和颜色格式 src.img.h = buffers.ver_stride ?: buffers.h; src.img.format = buffers.format; src.img.base = (void*)(intptr_t(buffers.heap->base()) + offset); src.img.handle = 0; gralloc_module_t const * module = LayerBuffer::getGrallocModule(); if (module && module->perform) { // 根据情况调用 int err = module->perform(module, // 调用perform,传入参数 GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER, buffers.heap->heapID(), bufferSize, offset, buffers.heap->base(),&src.img.handle); mSupportsCopybit = (err == NO_ERROR); } }
这里调用的perform是gralloc_module_t的一个可选实现的函数指针,如果当前使用的gralloc模块中实现了这个函数指针,则在这里调用函数。使用gralloc模块中的特殊命令,可以获得加速效果。
Layer和LayerBuffer的功能交由上层,它们执行显示的最终处理。LayerDim和LayerBlur部分则是两个类似特殊的图层,分别实现变暗和模糊的效果,它们都通过调用OpenGL的相应接口进行特殊的效果处理。
3.Surface的JNI
Surface的JNI提供对android.view中SurfaceSession和Surface两个类的本地支持。Surface的JNI封装了Surface和SurfaceComposerClient两个类。
android_view_Surface.cpp片段如下所示:
#include <surfaceflinger/SurfaceComposerClient.h> #include <surfaceflinger/Surface.h> const char* const kSurfaceSessionClassPathName = "android/view/SurfaceSession"; // android.view.SurfaceSession const char* const kSurfaceClassPathName = "android/view/Surface"; // android.view.Surface static JNINativeMethod gSurfaceSessionMethods[] = { {"init", "()V", (void*)SurfaceSession_init }, // 初始化Surface {"destroy", "()V", (void*)SurfaceSession_destroy }, // 销毁Surface {"kill", "()V", (void*)SurfaceSession_kill }, // 杀死Surface }; static JNINativeMethod gSurfaceMethods[] = { {"lockCanvasNative", "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;", (void*)Surface_lockCanvas }, // 锁住画布 {"unlockCanvasAndPost", "(Landroid/graphics/Canvas;)V", (void*)Surface_unlockCanvasAndPost }, // 解锁画布并发送 {"setLayer", "(I)V", (void*)Surface_setLayer }, // 设置层 {"setPosition", "(II)V",(void*)Surface_setPosition }, // 设置位置 {"setSize", "(II)V",(void*)Surface_setSize }, // 设置尺寸 // 省略部分内容 };
SurfaceSession负责Surface系统的初始化和销毁。Surface类与Surface本地类相对应,封装了各个接口函数,其中"lockCanvasNative"和"unlockCanvasAndPost"是显示的关键所在,前者锁住并绘制,后者解锁并显示。Surface的JNI的实现和android.graphics包中的Canvas类也有联系。
↘4.2.4 Java层的Surface的处理
Surface的Java部分的内容在android.view包中,提供了图层的底层处理、全局管理和在控件中使用等几个方面。Suface类的核心内容完成对基本UI系统的支持,SurfaceView类则提供给Java层作为直接显示内存的接口。
1.核心内容
Android框架层中与Suface相关的几个核心文件如下所示。
·SurfaceSession.java:SurfaceSession类是一个内部类,具有JNI部分。
·Surface.java:Surface类是主要的类,具有JNI部分。
·SurfaceHolder.java:SurfaceHolder接口,表示Surface类的封装。
SurfaceSession比较简单,是对本地内容的封装,用于创建图层的“会话”,实际上相当于全局的初始化和销毁。
Surface既是一个表示图层的句柄,也是连接Java本地层的主要手段,Surface中核心的方法lockCanvas()和unlockCanvasAndPost()根本上就是从本地实现的。
Surface类中定义几个常量:
public static final int FX_SURFACE_NORMAL = 0x00000000; // 普通 public static final int FX_SURFACE_BLUR = 0x000l0000; // 透明模糊 public static final int FX_SURFACE_DIM = 0x00020000; // 透明变暗 public static final int FX_SURFACE_MASK = 0x000F0000;
这几个表示图层类型的常量和本地定义的有对应关系。Surface构造函数中int类型的flags参数就表示了这个数值。Surface类的构造函数不是API,在应用程序层使用Surface也不会通过new得到,而是通过SurfaceHolder接口得到。
SurfaceHolder接口的主要内容如下所示:
public interface SurfaceHolder { public static final int SURFACE_TYPE_NORMAL = MEMORY_TYPE_NORMAL; @Deprecated public static final int SURFACE_TYPE_HARDWARE = MEMORY_TYPE_HARDWARE; @Deprecated public static final int SURFACE_TYPE_GPU = MEMORY_TYPE_GPU; public static final int SURFACE_TYPE_PUSH_BUFFERS = MEMORY_TYPE_PUSH_BUFFERS; public Canvas lockCanvas(); // 锁住Surface public Canvas lockCanvas(Rect dirty); public void unlockCanvasAndPost(Canvas canvas); // 解锁Surface public Surface getSurface(); // 获得Surface }
SURFACE_TYPE_NORMAL类型和SURFACE_TYPE_PUSH_BUFFERS等常量也和本地所定义的内容(ISurfaceComposerClient.h)具有对应关系,前者表示通常的图层,后者是推送Push Buffer方式的图层。
Surface几个类提供了Java框架层基本的窗口和控件(基类为View)的支持,也就是基本的显示功能。SurfaceSession在Java服务库的窗口管理器中建立唯一的实例,SurfaceHolder的实现者则在ViewRoot类中。
2.相关的内容
android.view包中的WindowManager.LayoutParams类,包含了内存类型定义和图层定义的常量。其中几个类型的定义如下所示:
public static final int MEMORY_TYPE_NORMAL = 0; @Deprecated public static final int MEMORY_TYPE_HARDWARE = l; @Deprecated public static final int MEMORY_TYPE_GPU = 2; public static final int MEMORY_TYPE_PUSH_BUFFERS = 3; public static final int FLAG_DIM_BEHIND = 0x00000002; public static final int FLAG_BLUR_BEHIND = 0x00000004;
此处对应的类型就是普通(Normal)、透明变暗(Dim)、透明模糊(Blur),用于不同种类层的处理。在应用程序的构建中,通过Windows类的setFlags()方法,可以将一个Activity设置的窗口图层设置为以上几个值。
android.view包的SurfaceView类是View继承者,即一个控件。SurfaceView提供了在Java层逐帧向Suface发送显示内容的机制,相当于其中具有SURFACE_TYPE_PUSH_BUFFERS类型的Suface实例。
SurfaceView内部具有一个mSurfaceHolder的实例,可采用如下方法得到SurfaceHolder:
public SurfaceHolder getHolder () {}
进而可以通过SurfaceHolder获得SurfaceView中的Surface。SurfaceView在实现的过程中,内部依托于一个窗口(IWindow)来完成。