Android显示vsync信号的虚拟化和处理流程

本文深入探讨Android 4.4后引入的黄油计划,重点关注SurfaceFlinger如何处理vsync信号的虚拟化。从vsync的生成到传递,详细解析了SurfaceFlinger的初始化过程,以及信号如何唤醒和驱动线程。通过分析EventThread、DispSyncThread和DispSyncSource的角色,展示了Android系统中vsync信号从发生到应用层的完整路径。

 

Android系统在4.4之后加入了黄油计划,surfaceflinger对显示的处理也变得复杂起来。由于添加了vsyn虚拟化机制,app将要显示的内容和surfaceflinger对显示内容的合成分成了两个部分,而两者开始的信号都是从vsync发出的。这里就涉及vsync信号的发生和传递,并且考虑到性能原因,信号的发生和传递都是按需进行的。因此,研究vsync信号的虚拟化及其处理,有助于理解线程的休眠唤醒和surfaceflinger的架构。

本文参考三篇文章:

https://blog.youkuaiyun.com/jinzhuojun/article/details/17293325

https://blog.youkuaiyun.com/houliang120/article/details/50908098

https://blog.youkuaiyun.com/kc58236582/article/details/52763534

一:SurfaceFlinger的初始化

init{    
// start the EventThread
    sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
            vsyncPhaseOffsetNs, true);
    mEventThread = new EventThread(vsyncSrc);
    sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
            sfVsyncPhaseOffsetNs, false);
    mSFEventThread = new EventThread(sfVsyncSrc);//先开线程
    mEventQueue.setEventThread(mSFEventThread);//然后在设置connection

    mEventControlThread = new EventControlThread(this);
    mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
}

 

Vsync发出后,调用SF的方法:

bool HWComposer::VSyncThread::threadLoop() {
    { // scope for lock
        Mutex::Autolock _l(mLock);
        while (!mEnabled) {
            mCondition.wait(mLock);
        }
    }

    const nsecs_t period = mRefreshPeriod;
    const nsecs_t now = systemTime(CLOCK_MONOTONIC);
    nsecs_t next_vsync = mNextFakeVSync;
    nsecs_t sleep = next_vsync - now;
    if (sleep < 0) {
        // we missed, find where the next vsync should be
        sleep = (period - ((now - next_vsync) % period));
        next_vsync = now + sleep;
    }
    mNextFakeVSync = next_vsync + period;

    struct timespec spec;
    spec.tv_sec  = next_vsync / 1000000000;
    spec.tv_nsec = next_vsync % 1000000000;

    int err;
    do {
        err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
    } while (err<0 && errno == EINTR);

    if (err == 0) {
        mHwc.mEventHandler.onVSyncReceived(0, next_vsync);
    }

    return true;
}

进入SF的方法:

void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
    bool needsHwVsync = false;

    { // Scope for the lock
        Mutex::Autolock _l(mHWVsyncLock);
        if (type == 0 && mPrimaryHWVsyncEnabled) {
            needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
        }
    }

    if (needsHwVsync) {
        enableHardwareVsync();
    } else {
        disableHardwareVsync(false);
    }
}

进入

bool DispSync::addResyncSample(nsecs_t timestamp) {
    Mutex::Autolock lock(mMutex);

    size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES;
    mResyncSamples[idx] = timestamp;

    if (mNumResyncSamples < MAX_RESYNC_SAMPLES) {
        mNumResyncSamples++;
    } else {
        mFirstResyncSample = (mFirstResyncSample + 1) % MAX_RESYNC_SAMPLES;
    }

    updateModelLocked();

    if (mNumResyncSamplesSincePresent++ > MAX_RESYNC_SAMPLES_WITHOUT_PRESENT) {
        resetErrorLocked();
    }

    if (runningWithoutSyncFramework) {
        // If we don't have the sync framework we will never have
        // addPresentFence called.  This means we have no way to know whether
        // or not we're synchronized with the HW vsyncs, so we just request
        // that the HW vsync events be turned on whenever we need to generate
        // SW vsync events.
        return mThread->hasAnyEventListeners();
    }

    return mPeriod == 0 || mError > errorThreshold;
}

进入

void DispSync::updateModelLocked() {
    if (mNumResyncSamples >= MIN_RESYNC_SAMPLES_FOR_UPDATE) {
        nsecs_t durationSum = 0;
        for (size_t i = 1; i < mNumResyncSamples; i++) {
            size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
            size_t prev = (idx + MAX_RESYNC_SAMPLES - 1) % MAX_RESYNC_SAMPLES;
            durationSum += mResyncSamples[idx] - mResyncSamples[prev];
        }

        mPeriod = durationSum / (mNumResyncSamples - 1);

        double sampleAvgX = 0;
        double sampleAvgY = 0;
        double scale = 2.0 * M_PI / double(mPeriod);
        for (size_t i = 0; 
VSYNC APP VSYNC RS(推测为 VSYNC_SF 信号,即 SurfaceFlinger 使用的信号)未及时触发,可能有以下原因: ### 硬件层面 - **HWC 故障**:负责产生硬件 Vsync 的是 HWC,若 HWC 出现故障,无法正常生成 VSYNC 事件,就会导致后续的 VSYNC_APP VSYNC_SF 信号无法正常产生。HWC 可生成 VSYNC 事件并通过回调将事件发送到 SurfaceFlinger,若硬件故障,后续流程必然受影响 [^1]。 - **硬件信号传输问题**:即使 HWC 正常产生了 VSYNC 信号,在将信号传递给 SurfaceFlinger 等上层模块时,可能会因为硬件连接不稳定、信号干扰等问题,导致信号丢失或延迟,使得 VSYNC_APP VSYNC_SF 信号不能及时触发 [^2]。 ### 系统层面 - **资源竞争**:系统中多个应用或进程同时竞争 CPU、GPU、内存等资源,会使负责处理 VSync 信号的进程得不到足够资源,影响信号处理分发,造成 VSYNC_APP VSYNC_SF 信号未及时触发。 - **系统负载过高**:当系统运行大量复杂任务时,整体负载过高,会导致系统响应变慢,无法及时处理 VSync 信号。例如在系统进行大规模数据处理、多任务并行时,可能会出现这种情况。 - **驱动程序问题**:图形驱动程序存在漏洞或与硬件不兼容,会使 GPU 无法正常工作,影响渲染性能 VSync 信号处理,导致 VSYNC_APP VSYNC_SF 信号未及时触发。 ### 软件层面 - **代码逻辑错误**:应用程序代码中存在死循环、大量内存泄漏等问题,会阻塞渲染线程,影响渲染速度 VSync 信号处理,导致信号未及时触发。在 Android 应用开发中,若在渲染线程中进行大量耗时操作,会阻塞渲染线程 [^1]。 ```java // 示例代码,模拟渲染过程中存在耗时操作 public class RenderThread extends Thread { @Override public void run() { while (true) { // 模拟耗时操作 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } // 渲染操作 renderFrame(); } } private void renderFrame() { // 渲染逻辑 } } ``` - **DispSync 问题**:DispSync(DispVsyncThread)将 Vsync 生成由 Choreographer SurfaceFlinger 使用的 VSYNC_APP VSYNC_SF 信号,若 DispSync 出现问题,如算法错误、调度异常等,会导致 VSYNC_APP VSYNC_SF 信号未及时生成分发 [^1]。 - **EventThread 异常**:EventThread 负责注册 App、SurfaceFlinger 的 VSync 请求分发 DispSyncThread 产生的虚拟化 VSync 信号到 App、SurfaceFlinger。若 EventThread 出现异常,如回调机制失效、请求处理错误等,会影响 VSync 信号的正常分发,导致信号未及时触发 [^2]。 ### 信号处理层面 - **VSync 信号不稳定**:VSync 信号不稳定可能是由于定时器定制内容导致定时器中断执行耗时,或者在 epoll SF 中 fd 时,由于设置的 timer 时间到了,而写 fd 内容延迟,导致 epoll 延迟从而 VSync 不稳定,打乱正常渲染节奏,使 VSYNC_APP VSYNC_SF 信号未及时触发 [^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值