android屏幕刷新之五

06-01 1731阅读

前言

接续 class NativeDisplayEventReceiver : public DisplayEventDispatcher,DisplayEventDispatcher作为显示事件的调度器,负责将AP侧的Vsync请求向下传递,以及将native层的Vsync事件向上分发。

DisplayEventDispatcher作为native层的操作对象,其路径为 framework/native/libs/gui/DisplayEventDispatcher.cpp。其作为NativeDisplayEventReceiver的父类对象,定义了诸多的虚函数,在native层调用时可传递信息至NativeDisplayEventReceiver的方法实现,借此完成native层的Vsync事件向上(java层)分发。

1 DisplayEventDispatcher.h

DisplayEventDispatcher的头文件定义了类的成员变量,函数类型,结构体等。路径为native/include/gui/DisplayEventDispatcher.h。定义了 android::DisplayEventDispatcher 类,它是 Java 层 DisplayEventReceiver 与 native SurfaceFlinger 分发 VSync、Hotplug、ModeChanged 等事件的桥梁。

主要封装了:

  • DisplayEventReceiver:用于从 SurfaceFlinger 收取 display 相关事件;
  • LooperCallback:用于将事件通过 epoll 机制分发回主线程;
  • 抽象的事件回调接口 dispatch* 系列函数;
  • VSync 监听与调度逻辑。

    1.1 成员变量说明

    参数说明
    sp mLoopernative Looper,对应 Java 中 MessageQueue
    DisplayEventReceiver mReceiver核心对象,内部包含 Binder IPC 连接与 fd
    bool mWaitingForVsync标记当前是否处于等待 vsync 的状态
    uint32_t mLastVsyncCount上一次收到的 VSync 编号
    nsecs_t mLastScheduleVsyncTime上一次请求 VSync 的时间
    std::vector mFrameRateOverrides当前帧率覆盖信息

    1.2 功能概述

    功能点说明
    LooperCallback被挂接到 Looper 的 epoll fd 回调对象
    DisplayEventReceiver实际与 SurfaceFlinger binder 通信的类,负责接收 display 事件
    initialize完成 binder 连接并注册 fd 到 looper
    scheduleVsync请求下次 VSync
    handleEventepoll 回调,处理所有事件并分发给子类
    dispatchVsync 等纯虚函数,由子类实现(如 NativeDisplayEventReceiver)来调用 Java 方法

    2 DisplayEventDispatcher.cpp

    2.1 初始化

    2.1.1 DisplayEventDispatcher初始化引用

    在NativeDisplayEventReceiver对象构建时引用了DisplayEventDispatcher,并为初始化DisplayEventDispatcher传递了重要参数:looper、vsyncSource、configChanged。据此判断,初始化DisplayEventDispatcher则是在构建NativeDisplayEventReceiver对象时进行的。

    2.1.2 初始化了哪些元素

    ① 调用 DisplayEventDispatcher 的构造方法来构造对象,同时将传入的 Looper 赋值给头文件中的 mLooper 保存。

    ② 调用 DisplayEventReceiver 的构造方法,传入 VSync 信号源等参数,并将构建的 DisplayEventReceiver 赋值给 mReceiver。

    ③ 将头文件中的 mWaitingForVsync 赋值为 false。

    2.1.3 构造函数

    DisplayEventDispatcher 初始化调度器本身及内部用于接收 VSync / Hotplug / ModeChanged 等显示事件的核心组件 —— DisplayEventReceiver。

    DisplayEventDispatcher::DisplayEventDispatcher(const sp& looper,
    gui::ISurfaceComposer::VsyncSource vsyncSource,
    EventRegistrationFlags eventRegistration,
    const sp& layerHandle)
          : mLooper(looper),
            mReceiver(vsyncSource, eventRegistration, layerHandle),
            mWaitingForVsync(false),
            mLastVsyncCount(0),
            mLastScheduleVsyncTime(0) {
        ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
    }
    

    参数解析:

    参数类型作用
    looperspNative 层 Looper,用于 epoll 机制调度 fd 事件(与 Java 的 MessageQueue 一一对应)
    vsyncSourceISurfaceComposer::VsyncSource指定接收哪一类 VSync,通常是 eVsyncSourceApp(主线程用)
    eventRegistrationEventRegistrationFlags注册感兴趣的事件类型,如 VSync、Hotplug、ModeChanged
    layerHandlesp绑定的 Layer,用于 per-layer vsync 精细调度(可为 null)

    成员变量的意义:

    • mLooper(looper)

      保存 Native Looper 对象,稍后会在 initialize() 中调用 looper->addFd() 注册监听事件。

    • mReceiver(vsyncSource, eventRegistration, layerHandle)

      接收事件的核心组件,与 SurfaceFlinger 的 Binder 通信(通过 ISurfaceComposer::createDisplayEventReceiver());对应的 epoll fd;接收事件缓冲区;但并未完成通信注册,通信是在 initialize() 中完成的。

    • mWaitingForVsync(false)

      表示当前是否在等待 VSync,在 scheduleVsync() 中设置为 true,事件到达后设为 false。

    • mLastVsyncCount(0)

      上一次收到的 VSync 编号;每收到一次 VSync,计数 +1,用于识别连续性或丢帧等

    • mLastScheduleVsyncTime(0)

      记录上一次调用 scheduleVsync() 的时间戳;用于做时间间隔检测、节流等。

      sp& looper如何传递?

      android屏幕刷新之五

      2.2 initialize()

      完成 DisplayEventDispatcher 的初始化工作,包括检查 DisplayEventReceiver 是否可用,以及将其关联的文件描述符注册到 Looper 中以便接收 epoll 事件(如 VSync)。

      返回一个 status_t 状态码:

      • OK (0) 表示初始化成功
      • 其他值表示错误(如 UNKNOWN_ERROR, BAD_VALUE 等
        status_t DisplayEventDispatcher::initialize() {
            // 检查 mReceiver 是否初始化成功
            status_t result = mReceiver.initCheck(); // 创建 binder 连接到 SurfaceFlinger(通过 mReceiver.initCheck()),initCheck() 是在构造后检查是否成功连接到服务和创建了 eventfd
            if (result) {
                ALOGW("Failed to initialize display event receiver, status=%d", result);
                return result;
            }
            if (mLooper != nullptr) {
                // 注册 mReceiver 的 fd 到 Looper 监听 VSync 事件, 调用 mLooper->addFd(...),将 mReceiver.getFd() 添加到 epoll
                int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);
                if (rc  
        

        【注1】

        ① DisplayEventReceiver对象自检,mReceiver.initCheck() 检查 DisplayEventReceiver 中的 mDataChannel 是否为空,从前面的分析可知 mDataChannel 的类型为 gui::BitTube。

        ② 判断 mLooper 是否为空,如不为空,则调用 Looper 的 addFd() 方法将 DisplayEventReceiver 中的 mDataChannel 的 mReceiveFd 加入到 mLooper 中,同时设置回调方法,用于监测事件。注意: addFd() 方法中第四个 this 是一个 LooperCallback 回调、这里传入当前 DisplayEventDispatcher,因为 DisplayEventDispatcher 继承 LooperCallback,当 mReceiveFd 有可读事件时将触发回调。

        【注2】

        监听 VSync 事件说明:

        • 调用 mReceiver.getFd() 获取其底层 epoll/eventfd 文件描述符;

        • 将该 fd 注册到 Looper 中,监听 EVENT_INPUT 事件;

        • 当 fd 可读(即 SurfaceFlinger 写入事件)时,Looper 会调用 handleEvent();

          【注】关于mLooper->addFd,详细可以看 Handler消息机制-Looper(system) 关于looper的分析。

          参数含义
          int fdVSync 使用的 eventfd
          int ident标识符,一般为 0
          int eventsEVENT_INPUT 表示监听可读事件(VSync 就是写入通知)
          Looper_callbackFunc callbackthis当前对象作为回调,实现了 handleEvent()
          void* data用户数据,这里为 NULL

          2.3 scheduleVsync()

          请求下一帧的 VSync,并设置等待状态。在 Android 的渲染机制中,Choreographer 和其他组件会调用这个函数,以注册对下一次 VSync 信号 的监听 —— 通常用于驱动一次渲染流程。

          status_t DisplayEventDispatcher::scheduleVsync() {
              // 表示当前是否已请求等待一个 VSync,避免重复调度,每一帧只调度一次。
              if (!mWaitingForVsync) {
                  ALOGV("dispatcher %p ~ Scheduling vsync.", this);
                  // Drain all pending events.
                  nsecs_t vsyncTimestamp;
                  PhysicalDisplayId vsyncDisplayId;
                  uint32_t vsyncCount;
                  VsyncEventData vsyncEventData;
                  // 尝试从 DisplayEventReceiver 的内部缓冲区中拉取已经积压但尚未处理的事件
                  if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
                      ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", this,
                            ns2ms(static_cast(vsyncTimestamp)));
                  }
                  // 向 SurfaceFlinger 请求下一次 VSync
                  status_t status = mReceiver.requestNextVsync();
                  if (status) {
                      ALOGW("Failed to request next vsync, status=%d", status);
                      return status;
                  }
                  mWaitingForVsync = true; // 设置等待状态,防止下一次重复调用
                  mLastScheduleVsyncTime = systemTime(SYSTEM_TIME_MONOTONIC); // 记录调度时间,可用于后续分析帧间隔、掉帧等行为
              }
              return OK;
          }
          

          2.4 handleEvent(int, int events, void*)

          DisplayEventDispatcher::handleEvent(…) 是 DisplayEventDispatcher 类作为 LooperCallback 的核心回调函数,负责响应 epoll 事件(fd 可读等)并处理 VSync 信号。

          在Looper对 epoll 事件进行处理的过程中,会取出每个 Request 并调用其 callback 回调的 handleEvent() 方法。该回调就是向 Looper 中添加 fd 时作为 LooperCallback 回调一并传入的 DisplayEventDispatcher 实现类。因此,也就是在epoll 事件进行处理时回调 DisplayEventDispatcher::handleEvent 函数。如果读取到 VSync,会调用子类实现的 dispatchVsync(…) 通知 Java 层。

          int DisplayEventDispatcher::handleEvent(int, int events, void * )

          • 第一个参数是 fd(未使用)
          • 第二个是 events,表示触发的 epoll 事件掩码
          • 第三个是用户数据 void*(此处未用)
            int DisplayEventDispatcher::handleEvent(int, int events, void*) {
                // 处理错误事件
                if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
                    ALOGE("Display event receiver pipe was closed or an error occurred.  "
                          "events=0x%x",
                          events);
                    return 0; // remove the callback
                }
                // 非 EVENT_INPUT 事件(不应触发)
                if (!(events & Looper::EVENT_INPUT)) {
                    ALOGW("Received spurious callback for unhandled poll event.  "
                          "events=0x%x",
                          events);
                    return 1; // keep the callback
                }
                // Drain all pending events, keep the last vsync.
                // 定义一组变量用于保存最近一次 VSync 信息
                nsecs_t vsyncTimestamp;
                PhysicalDisplayId vsyncDisplayId;
                uint32_t vsyncCount;
                VsyncEventData vsyncEventData;
                // 调用 processPendingEvents(...) 会尝试从 DisplayEventReceiver 中读取事件并填充上述参数
                if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
                    ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64
                          ", displayId=%s, count=%d, vsyncId=%" PRId64,
                          this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
                          vsyncEventData.preferredVsyncId());
                    // 有 Vsync 响应
                    mWaitingForVsync = false; // 将 mWaitingForVsync 设为 false,表示当前 VSync 已处理
                    mLastVsyncCount = vsyncCount; // 记录帧数;
                    dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData); // 调用 dispatchVsync(...),将数据上报到 Java 层
                }
                // VSync 丢失容错机制
                if (mWaitingForVsync) {
                    // -----> 若 mWaitingForVsync 仍为 true(即 scheduleVsync() 后未收到实际事件)  WAITING_FOR_VSYNC_TIMEOUT) {
                        ALOGW("Vsync time out! vsyncScheduleDelay=%" PRId64 "ms", ns2ms(vsyncScheduleDelay));
                        // 手动构造一个“伪造”的 VSync,调用 dispatchVsync() 保证应用不中断。
                        mWaitingForVsync = false;
                        dispatchVsync(currentTime, vsyncDisplayId /* displayId is not used */,
                                      ++mLastVsyncCount, vsyncEventData /* empty data */);
                    }
                }
                // 1 表示 Looper 继续监听该 FD
                return 1; // keep the callback
            }
            

            总结:

            内容描述
            主动触发被 epoll(Looper)唤醒,表示 DisplayEventReceiver 有输入
            核心行为读取 VSync 事件并转发(或热插拔等)
            特殊情况管道断开、epoll 错误、伪造 VSync(超时)
            最终派发调用虚函数 dispatchVsync(),由子类(如 NativeDisplayEventReceiver)实现并通知 Java

            2.5 processPendingEvents

            Native 层用于处理 Display 事件缓存队列(主要是 VSync)的关键方法。这个方法的目的是从 DisplayEventReceiver 的内部事件缓冲队列中读取并解析所有事件,并根据类型分发处理(VSync、Hotplug、ModeChange、FrameRateOverride 等)。如果有 VSYNC 事件,还会通过输出参数传出其时间戳、显示 ID、计数、附加数据。

            2.5.1 函数定义

            bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp,
               PhysicalDisplayId* outDisplayId,
               uint32_t* outCount,
               VsyncEventData* outVsyncEventData) 
            
            参数类型说明
            outTimestampnsecs_t*输出参数,用于返回最新的 vsync 时间戳
            outDisplayIdPhysicalDisplayId*输出参数,返回产生该事件的物理显示 ID
            outCountuint32_t*输出参数,vsync 的帧计数(递增)
            outVsyncEventDataVsyncEventData*输出参数,vsync 附带的时序数据

            2.5.2 源码分析

            bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp,
               PhysicalDisplayId* outDisplayId,
               uint32_t* outCount,
               VsyncEventData* outVsyncEventData) {
                // gotVsync 标志用于判断是否读取到了 VSYNC 事件
                bool gotVsync = false;
                // 定义事件读取缓存 buf,容量为 EVENT_BUFFER_SIZE(默认值 100)
                DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
                ssize_t n;
                // 循环读取事件(阻塞在 epoll 上已触发、非阻塞读取)
                // mReceiver.getEvents(...) 从底层内核中的 event 缓存读取最多 EVENT_BUFFER_SIZE 个事件
                while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
                    ALOGV("dispatcher %p ~ Read %d events.", this, int(n));
                    mFrameRateOverrides.reserve(n); // 为帧率覆盖事件预留空间(防止 vector 多次扩容)
                    for (ssize_t i = 0; i  VSYNC 事件
                                // Later vsync events will just overwrite the info from earlier
                                // ones. That's fine, we only care about the most recent.
                                gotVsync = true; // 设置标志 gotVsync = true
                                // 将 timestamp / displayId / vsync count / vsync event data 输出出去
                                *outTimestamp = ev.header.timestamp;
                                *outDisplayId = ev.header.displayId;
                                *outCount = ev.vsync.count;
                                *outVsyncEventData = ev.vsync.vsyncData;
                                // 注意:while 循环中,如果有多个 VSync 事件,只保留最后一个(覆盖掉旧的),因为应用只关心最近一次 VSync
                                break;
                            case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: // ===> 热插拔事件(HDMI、屏幕连接)
                                // 回调 dispatchHotplug --> NativeDisplayEventReceiver 的虚函数实现会调 Java 的 onHotplug()
                                dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
                                break;
                            case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: // ===> 显示模式变更(刷新率、分辨率)
                                // dispatchModeChanged --> Java 的 onModeChanged()
                                dispatchModeChanged(ev.header.timestamp, ev.header.displayId,
                                                    ev.modeChange.modeId, ev.modeChange.vsyncPeriod);
                                break;
                            case DisplayEventReceiver::DISPLAY_EVENT_NULL: // ===> Null Event(特殊用于 poke Looper)
                                dispatchNullEvent(ev.header.timestamp, ev.header.displayId);
                                break;
                            case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE: // ===> 帧率覆盖信息(某个 UID 运行时强制帧率)
                                mFrameRateOverrides.emplace_back(ev.frameRateOverride);
                                break;
                            case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH: // ===> 帧率覆盖信息的刷新时机
                                // 将已收集的 FrameRateOverride 向上分发,使用 std::move 避免拷贝
                                dispatchFrameRateOverrides(ev.header.timestamp, ev.header.displayId,
            std::move(mFrameRateOverrides));
                                break;
                            default:
                                ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
                                break;
                        }
                    }
                }
                if (n  
            

            总结:

            内容描述
            功能读取并分发 SurfaceFlinger 通过 binder 发送过来的 VSync 等事件
            输入来源DisplayEventReceiver::getEvents(),从内核 epoll 的 socket 缓冲区读取
            支持事件VSync / Hotplug / ModeChange / Null / FrameRateOverride
            多个事件会逐个处理,最终只保留最新一次 VSync 信息给输出参数
            被谁调用scheduleVsync() 和 handleEvent() 都会调用它来清空旧事件

            2.6 DisplayEventDispatcher 的核心职责

            ✅ 小结

            职责说明
            封装 epoll 注册使用 Looper 管理 fd
            封装 binder 接收使用 DisplayEventReceiver 从 SF 接收事件
            统一事件分发提供虚接口供子类实现,确保所有事件均回调
            事件打包解码通过 processPendingEvents() 解码事件
            支持 VSync 调度提供 scheduleVsync() 向 SF 注册下一次请求
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码