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
相关推荐
怪奇云呼军2 小时前
从声音特征到 CRM 回流:闪电智能 Voice Agent 沟通策略自适应系统 v1 实战
android·人工智能·python·音视频·语音识别
一笑的小酒馆4 小时前
Android视频直播播放器简单封装
android
工会代表6 小时前
安卓手机搭建SOCKS5代理教程
android
雨白6 小时前
Android AOP 切面编程实战:优雅地处理全局断网拦截
android·架构
huluang8 小时前
专业级安卓现场取证利器:拍照取证(PaiZaoXue),补齐行业取证工具核心短板
android·数码相机
奇特認8 小时前
MySQL集群技术 4.高可用之组复制 (MGR)
android
阿pin8 小时前
Android随笔-SurfaceFlinger
android·surfaceflinger
洋不写bug8 小时前
JavaComparable、Comparator、Cloneable接口解析,深拷贝浅拷贝详细解析
android·java·开发语言
小孔龙9 小时前
Android 应用间 UI 刷新与合成
android
XiaoLeisj10 小时前
Kotlin Flow:冷流收集、并行订阅、emit 推送、delay 延迟、collect 全量收集与 collectLatest 的实时数据处理
android·kotlin·android jetpack·协程·flow