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)来完成。