深入理解 Android:Surface 系统

FrameBufferDevice:

  • FrameBuffer 就是存储图像帧数据的缓冲区;

  • FrameBufferDevice 是 Linux 平台的虚拟显示设备,为真实设备提供统一框架,这样应用层通过标准的 ioctlmmap 系统调用就可以操作显示设备;

  • FrameBuffer 中的缓冲区就是通过 mmap 把设备中的显存映射到用户空间的:在这块缓冲区写数据,就相当于在屏幕上绘制;

Window 和 View:

  • Window 是抽象基类,用于控制顶层窗口的外观和行为(背景、标题栏、默认按键处理等);

  • View 是基本的 UI 单元,占据屏幕一块矩形区域,用于绘制和事件处理;

ViewRoot:

  • ViewRoot 继承自 Handler (可处理消息),并实现了 ViewParent 接口(不处理绘制、没有 onDraw());

  • ViewRoot 内部有一个 IWindow.Stub 对象(用于 Binder 通信)、View 对象和 Surface 对象(用于 View 绘制,有一块 Raw buffer,可以和 SurfaceFlibger 交互);

  • ViewRoot 构造方法调用 getWindowSession()ViewRootWindowManagerService 关联起来;

  • ViewRoot::setView():

    1. 将传入的 View 指向 PhoneWindowDecorView;

    2. 调用 requestLayout(), 向 Handler 发送 DO_TRAVERSAL 消息; 收到消息后调用 IWindowSessionrelayout()

    3. 调用 draw(),先从 Surface 中 lock 一块 Canvas,然后让 View 绘制,最后调用 unlockCanvasAndPost();

    4. 调用 IWindowSession的add() 方法,这是一个跨进程的 Binder 通信;

  • ViewRoot 与其子 View 共用一个 Canvas,但 lockCanvas() 得到的内存不同;它们一般也共用一个 SurfaceSurfaceView 除外,它在单独线程绘制);

Activity 的创建:

  1. Activity 主线程 ActivityThread 类的 handleLaunchActivity() 方法用于创建 Activity;

  2. ClassLoader 和反射创建 Activity 对象,并调用其 onCreate();

  3. 调用 Activityattach() 方法,内部调用 PolicyManagermakeNewWindow() 方法创建 PhoneWindow 对象;

  4. 调用 setWindowManager(),创建 LocalWindowManager 对象,内部保存 WindowManager 对象,而其实际类型为 WindowManagerImpl;

  5. setContentView() 设置的 View 其实是 DecorView 的子 ViewDecorViewFrameLayout 类型的 ViewGroup,处理了标题栏显示等工作;

  6. LocalWindowManageraddView() 方法内部创建了 ViewRoot 对象;

WindowManagerService:

  • openSession():创建内部类 Session 对象,可用于响应 Binder 通信中的请求;

  • addWindow(): 创建 WindowStateSurfaceSession 对象,窗口数 mNumWindow 自增;

  • relayoutWindow():

    1. 先创建本地 Surface,并分别调用 Surface.openTransaction()closeTransaction() 进行事务处理;

    2. 调用 SurfacecopyFrom() 拷贝本地 Surface 的信息;

    3. 调用 SurfacewriteToParcel() 写入数据;

  • 对按键事件的分发:

    1. WMS 所在的 SystemServer 进程接收到事件;

    2. WMS 找到 UI 位于屏幕顶端的进程所对应的 IWindow 对象;

    3. 调用 IWindow 对象的 dispatchKey() 分发事件;

    4. ViewRoot 找到真正处理该事件的 View,并调用其 dispatchKey();

Java 层 Surface:

  • 无参构造方法:创建一个 CompatibleCanvas 对象,而 Canvas 一般会封装一个 Bitmap 对象用于绘制;

  • 有参构造方法:

    1. 创建一个 CompatibleCanvas 对象,并调用本地 init() 方法;

    2. 创建一个 SurfaceComposerClient,并调用其 createSurface() 函数得到 SurfaceControl 对象;

    3. 调用 SurfaceControl 对象的 writeSurfaceToParcel() 把数据写入 Parcel 包;

    4. 根据 Parcel 包构造一个 Surface 对象,并保存到 Java 层,这样 ViewRoot 就得到一个 Native 的 Surface 对象;

  • lockCanvas()

    1. 取到 Native 的 Canvas 对象,并根据 dirtyRect (需要重绘的矩形区域)创建 Region 对象;

    2. 调用 Native 层 Canvaslock() 函数;

    3. 取出 Java 层的 CompatibleCanvas 对象,给 Bitmap 指定存储区域,并将 BitmapCanvas 绑定;

Native 层 Surface:

  • 构造函数:定义 GraphicBuffer 数组,读取 Parcel 中的数据,创建 SurfaceComposerClient 对象;

  • lock()

    1. 设置 usage 标志,用于 GraphicBuffer 分配缓冲;

    2. 调用 dequeueBuffer():调用 SharedBufferClientdequeueBuffer(),并调用 LayerrequestBuffer() 得到 GraphicBuffer;

    3. 调用 lockBuffer():调用 SharedBufferClientlock()

    4. 调用 copyBlt():把 FrontBuffer(mPostedBuffer) 中的旧数据拷贝回 BackBuffer(叠加后防止重复绘制);

  • unlockAndPost():返回 GraphicBuffer 编号,调用 queueBuffer(),设置 DirtyRegion,更新写位置;

SurfaceComposerClient:

  • SurfaceComposerClient 建立了和 SurfaceFlinger 交互的通道:构造函数会调用 SurfaceFlingercreateConnection() 创建连接;

  • 初始化时会创建 BpSurfaceFlinger 类型的 mSignalServer 对象,用于在客户端更新 BackBuffer 后通知 SurfaceFlinger 进行 PageFlipping 和输出;

  • createSurface():创建 ISurface 对象,并以其为参数创建 SurfaceControl 对象(封装了一些函数,可以方便地调用 SurfaceComposerClientISurface 提供的函数);

  • openTransaction():主要是用 AutoLock 控制计数变量 mTransactionOpen 自增;

  • setPosition():修改控制 Surface 在屏幕上的位置和宽高信息的 layer_state_t

  • closeGlobalTransaction()

    1. 先调用 SurfaceFlinger.openGlobalTransaction():也是一个计数控制;

    2. 然后调用 SurfaceFlinger.setClientState():遍历所有 Layer,调用其 setPosition(),最后设置 flag;

    3. 最后调用 SurfaceFlinger.closeGlobalTransaction():调用 siginalEvent() 提交事务;

SurfaceFlinger:

  • SurfaceFlinger 驻留于 system_server 进程,是从 Thread 派生的,会单独启用一个工作线程;

  • onFirstRef()

    1. 第一次创建引用时调用;

    2. 首先启用工作线程,然后调用 Barrier (封装了 MutexCondition 的同步类)的 wait();

  • createConnection()

    1. 创建 Client,并保存到 ClientsMapClient 内部会创建一块共享内存 MemoryHeapBase,以及用于读写控制的 SharedClient 对象;

    2. 根据 Client 创建用于 Binder 通信的 BClientBClient 派生于 ISurfaceFlingerClient,用于接收客户端请求,并提交给 SurfaceFlinger;

  • createSurface(): 根据传入的 flag 创建 PushBuffer / Normal / Blur / Dim 等不同类型的显示层(LayerBaseClient);

  • readyToRun()

    1. 创建 GraphicPlane (目前只支持一块屏幕),并设置 HAL 对象 DisplayHardware;

    2. 创建共享内存 MemoryHeapBase;

    3. 获取屏幕信息,调用 OpenGL 相关函数;

    4. 调用 Barrier.open() 触发同步条件;

    5. 调用 property_set 设置 boot 动画;

  • SurfaceFlinger 创建 FrameBuffer,并将各个 Surface 传输的数据通过 GraphicBuffer 混合后,再由自己传输到 FrameBuffer;

  • threadLoop() 线程循环:

    1. 调用 waitForEvent():等待 INVALIDATE 重绘消息(unlockCanvasAndPost() 会调用 signal(),进而调用 mEventQueue.invalidate());

    2. 调用 handleTransaction():调用 handleTransactionLocked() 处理事务,调用每个 Layer.ditch() 丢弃被 hide 的层;

    3. 调用 handlePageFlip():调用 Layer.lockPageFlip() 根据 FrontBuffer 数据生成 Texture;调用 Layer.unlockPageFlip() 做清理工作;

    4. 调用 handleRepaint():获取 DisplayHardware,计算 DirtyRegion;按 Z 轴顺序由里到外依次调用 Layer.draw() 函数;

    5. 调用 unlockClients():调用 Layer.unlock(mFrontBufferIndex),释放占用的 FrontBuffer;

    6. 调用 postFrameBuffer():调用 DisplayHardware.flip(),交换 buffer,使图像显示;

  • handleTransactionLocked() 事务处理:

    1. 获得所有显示层数组 layersSortedByZ

    2. 如需要遍历,则调用所有 Layer.onTransaction();

    3. 处理横竖屏切换和 layersRemoved;

    4. 调用 commitTransaction():调用同步变量的 broadcast() 函数;

SharedClient 与 SharedBuffer 家族:

  • 每个 SurfaceFlinger 内部定义一个跨进程共享的 SharedClient;

  • SharedClient 内部的 SharedBufferStack 数组有 31 个元素,对应 31 个显示层,每层的读写步调由 SharedBufferStack 内部的成员变量控制;

  • SharedBuffer 家族在 SurfaceFlinger 端的代表是 SharedBufferServer, 在 Activity 端的代表是 SharedBufferClient;

LayerBaseClient:

  • LayerBaseClient 继承自 LayerBase,且有四个派生类:LayerLayerBufferLayerDimLayerBlur

  • LayerBaseClient 定义了内部类 Surface,它继承自 ISurface,支持 Binder 通信;

  • 构造函数:使用 SharedClient 对象创建 SharedBufferServer 对象;

  • setBuffs():创建用于 PageFlipping 的两个 GraphicBuffer 对象:FrontBuffer 和 BackBuffer;

  • addLayer_l():把新创建的 Layer 加入自己的 Z 轴 Layer 数组:layersSortedByZ

  • onDraw(): 调用 OpenGL 相关函数绘制;

GraphicBuffer:

  • 继承自 LightRefBase 使它支持引用计数;

  • 继承自 Flattenable 使它支持序列化和反序列化,可封装于 Parcel 中用于 Binder 通信:

    1. 响应端 BnSurfaceonTransact() 方法中 reply.write(*buffer) 会触发 flatten() 序列化;

    2. 请求端 BpSurfacerequestBufferreply.read(*buffer) 会触发 unflatten() 反序列化;

  • 内部的 GraphicBufferAllocator 对象用于内存分配;


参考:

《深入理解 Android: 卷 I》