Android窗口Surface简介

创建流程

  • 应用程序窗口对应一个Surface(Surface.java)
  • Surface由每个应用进程的ViewRootImpl持有
  • Surface最初初始化为一个空Surface
  • Surface的初始化发生在第一次relayoutWindow
css 复制代码
[View.invalidate]  
    ↓  
[逐级传递到 ViewRootImpl]  
    ↓  
[ViewRootImpl.scheduleTraversals()]  
    ↓  
[插入同步屏障,注册 VSYNC 回调]  
    ↓  
[VSYNC 信号到达 → 执行 doTraversal() → performTraversals() → relayoutWindow]
    ↓
[执行updateBlastSurfaceIfNeeded()]
    ↓
[创建BLASTBufferQueue → mBlastBufferQueue.createSurface() → mSurface.transferFrom(blastSurface)]

接下来分析Java层BLASTBufferQueue的createSurface创建流程

BLASTBufferQueue.createSurface

  • Java层的createSurface对应到jni中的nativeGetSurface
  • jni层中,通过BLASTBufferQueue::getSurface获取Surface
  • 在BLASTBufferQueue::getSurface中创建并返回了一个BBQSurface
c++ 复制代码
sp<Surface> BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) {
    std::lock_guard _lock{mMutex};
    sp<IBinder> scHandle = nullptr;
    if (includeSurfaceControlHandle && mSurfaceControl) {
        scHandle = mSurfaceControl->getHandle();
    }
    return new BBQSurface(mProducer, true, scHandle, this);
}
  • BBQSurface关联了BBQ中的生产者、SurfaceControl、还有BBQ自己本身
  • Java层窗口对应的Surface在native层包装的是BBQSurface

将Surface设置给hwui

  • 接着上一节,在performTraversals()中创建Surface后,接着会进行更新Surface
c++ 复制代码
private void performTraversals() {
    ...
    } else if ((surfaceReplaced || surfaceSizeChanged || updateSurfaceNeeded)
                        && mSurfaceHolder == null
                        && mAttachInfo.mThreadedRenderer != null
                        && mSurface.isValid()) {
        mFullRedrawNeeded = true;
        try {
            // Need to do updateSurface (which leads to CanvasContext::setSurface and
            // re-create the EGLSurface) if either the Surface changed (as indicated by
            // generation id), or WindowManager changed the surface size. The latter is
            // because on some chips, changing the consumer side's BufferQueue size may
            // not take effect immediately unless we create a new EGLSurface.
            // Note that frame size change doesn't always imply surface size change (eg.
            // drag resizing uses fullscreen surface), need to check surfaceSizeChanged
            // flag from WindowManager.
            mAttachInfo.mThreadedRenderer.updateSurface(mSurface);
        } catch (OutOfResourcesException e) {
            handleOutOfResourcesException(e);
            mLastPerformTraversalsSkipDrawReason = "oom_update_surface";
            return;
        }
    }
}
  • 从java层一层层调用到SkiaPipeline
  • 需要注意的一点是在jni层,会将Surface转成ANativeWindow,在hwui模块中只能感知到ANativeWindow的存在
  • 在skiapipeline中根据opengl、vulkan后端,区分不同的流程(Android15中已经默认走vulkan)
    • (opengl),在SkiaOpenGLPipeline中调用setSurface,然后是EglManager.createSurace将ANativeWindow转成EGLSurface

渲染

  • 还有一条非常隐蔽的线,在SkiaPipeline renderFrame渲染每帧内容时,用的是SkSurface,SkSurface与EGLSurface的关联是源码中看不到的
  • 在SkiaPipeline中通过MakeFromBackendRenderTarget创建SkSurface时,需要传入GrBackendRenderTarget(封装了 EGLSurface 的帧缓冲区对象 FBO
相关推荐
测试员周周3 分钟前
【Appium 系列】第14节-断言与验证 — Validator 的设计
android·人工智能·python·功能测试·ios·单元测试·appium
赏金术士1 小时前
Android 动画对比指南:View 系统 vs Jetpack Compose
android·kotlin·compose
我命由我123451 小时前
C++ - 面向对象 - 析构函数
android·c语言·开发语言·c++·visualstudio·visual studio·android runtime
失眠的咕噜2 小时前
PDA 安卓设备上传多张图片
android·前端·javascript
zb200641202 小时前
Laravel6.x新特性全解析
android
plainGeekDev2 小时前
Kotlin核心:空安全都搞不明白,还敢说熟练Kotlin?
android·面试·kotlin
huaCodeA3 小时前
Android面试-Flow相关
android·面试·职场和发展
繁星星繁3 小时前
Python基础语法(二)
android·服务器·python
Lang-12104 小时前
Frida + Android Hook 完整指南
android·逆向·hook·frida
jzlhll1234 小时前
Kotlin 协程高级用法之 NonCancellable
android·开发语言·kotlin