Android VSync信号产生过程源码分析

在上一篇Android Project Butter分析中介绍了Android4.1通过引入VSync机制来改善显示效果,并分析了VSync机制的原理。本文主要分析VSync信号的产生过程。VSync信号产生有两种方式,一种是硬件中断产生,另一种是使用软件模拟产生,至于使用何种方式产生VSync信号,就和硬件系统配置有关。在Android4.1以后的版本中,定义了HWComposer硬件抽象模块来负责产生VSync信号。HWComposer硬件抽象层定义:

hardware\libhardware\modules\hwcomposer\hwcomposer.cpp

hwc_module_t HAL_MODULE_INFO_SYM = {
    common: {
        tag: HARDWARE_MODULE_TAG,
        version_major: 1,
        version_minor: 0,
        id: HWC_HARDWARE_MODULE_ID,
        name: "Sample hwcomposer module",
        author: "The Android Open Source Project",
        methods: &hwc_module_methods,
    }
};

注册的硬件抽象模块方法定义如下:

static struct hw_module_methods_t hwc_module_methods = {
    open: hwc_device_open
};

关于为硬件抽象模块HWComposer定义的数据结构之间的关系如下下图所示:

《Android VSync信号产生过程源码分析》

在初始化DisplayHardware对象时,会创建一个HWComposer对象:

void DisplayHardware::init(uint32_t dpy)
{
	...
    // initialize the H/W composer
    mHwc = new HWComposer(mFlinger, *this, mRefreshPeriod);
    if (mHwc->initCheck() == NO_ERROR) {
        mHwc->setFrameBuffer(mDisplay, mSurface);
    }
}

这里使用SurfaceFlinger,DisplayHardware对象及屏幕刷新周期来构造HWComposer对象,HWComposer的构造过程如下:

frameworks\native\services\surfaceflinger\DisplayHardware\HWComposer.cpp

HWComposer::HWComposer(const sp<SurfaceFlinger>& flinger,EventHandler& handler,nsecs_t refreshPeriod)
    : mFlinger(flinger),
      mModule(0), mHwc(0), mList(0), mCapacity(0),
      mNumOVLayers(0), mNumFBLayers(0),
      mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE),
      mEventHandler(handler),
      mRefreshPeriod(refreshPeriod),
      mVSyncCount(0), mDebugForceFakeVSync(false)
{
    char value[PROPERTY_VALUE_MAX];
    property_get("debug.sf.no_hw_vsync", value, "0");
    mDebugForceFakeVSync = atoi(value);
	//是否需要软件模拟VSync
    bool needVSyncThread = false;
	//加载HWComposer硬件抽象模块
    int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
    ALOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID);
    if (err == 0) {
		//打开HWComposer硬件抽象模块
        err = hwc_open(mModule, &mHwc);
        if (err == 0) {
			//打开成功,注册回调函数
            if (mHwc->registerProcs) {
                mCBContext.hwc = this;
                mCBContext.procs.invalidate = &hook_invalidate;
                mCBContext.procs.vsync = &hook_vsync;
                mHwc->registerProcs(mHwc, &mCBContext.procs);
                memset(mCBContext.procs.zero, 0, sizeof(mCBContext.procs.zero));
            }
            if (mHwc->common.version >= HWC_DEVICE_API_VERSION_0_3) {
                if (mDebugForceFakeVSync) {
                    // make sure to turn h/w vsync off in "fake vsync" mode
                    mHwc->methods->eventControl(mHwc, HWC_EVENT_VSYNC, 0);
                }
            } else {
                needVSyncThread = true;
            }
        }
    } else {
        needVSyncThread = true;
    }
	//如果HWComposer硬件抽象模块打开失败或者HWComposer硬件抽象模块的版本小于HWC_DEVICE_API_VERSION_0_3,则采用软件模拟产生VSync信号
    if (needVSyncThread) {
        //创建VSync产生线程VSyncThread
        mVSyncThread = new VSyncThread(*this);
    }
}

在构造HWComposer对象时,选择了VSync信号产生方式:1.硬件产生;2.软件模拟产生;假如当前系统可以成功加载HWC_HARDWARE_MODULE_ID=hwcomposer,并且通过这个库能顺利打开设备(hwc_composer_device_t),并且其版本号又大于HWC_DEVICE_API_VERSION_0_3的话,我们就采用硬件方式产生VSync,否则需要创建一个新的VSync线程来模拟产生信号。

1.硬件产生VSync信号过程

Android定义了hwcomposer硬件抽象模块来负责产生VSync信号,因此在使用硬件方式产生VSync信号时,需要首先加载并打开hwcomposer硬件抽象模块。硬件抽象模块的加载过程已经在
Android硬件抽象Hardware库加载过程源码分析详细分析了,因此在这里只介绍hwcomposer硬件模块的打开过程:

err = hwc_open(mModule, &mHwc);

mModule为hw_module_t类型变量,用于描述hwcomposer硬件抽象模块,参数mHwc的类型为hwc_composer_device_t,该结构用于描述hwcomposer硬件设备。

static inline int hwc_open(const struct hw_module_t* module,
        hwc_composer_device_t** device) {
    return module->methods->open(module,
            HWC_HARDWARE_COMPOSER, (struct hw_device_t**)device);
}

在定义hwcomposer硬件抽象层时,注册了该硬件抽象模块的打开回调函数hwc_device_open,其实现过程如下:

static int hwc_device_open(const struct hw_module_t* module, const char* name,struct hw_device_t** device)
{
    int status = -EINVAL;
    if (!strcmp(name, HWC_HARDWARE_COMPOSER)) {
        struct hwc_context_t *dev;
        dev = (hwc_context_t*)malloc(sizeof(*dev));
        /* initialize our state here */
        memset(dev, 0, sizeof(*dev));
        /* initialize the procs */
        dev->device.common.tag = HARDWARE_DEVICE_TAG;
        dev->device.common.version = 0;
        dev->device.common.module = const_cast<hw_module_t*>(module);
        dev->device.common.close = hwc_device_close;
        dev->device.prepare = hwc_prepare;
        dev->device.set = hwc_set;
        *device = &dev->device.common;
        status = 0;
    }
    return status;
}

打开hwcomposer硬件模块过程实际上是创建一个hwc_context_t对象,同时将该模块的回调函数注册到hwc_context_t对象中,如果mHwc->registerProcs不为空的话,我们注册硬件回调mCBContext.procs。当有事件产生时,比如vsync或者invalidate,硬件模块将分别通过procs.vsync和procs.invalidate来通知HWComposer。在这里可以创建一个线程专门负责响应VSync中断:

bool VSyncThread::threadLoop() {
    { // scope for lock
        Mutex::Autolock _l(mLock);
        while (!mEnabled) {
            mCondition.wait(mLock);
        }
    }
	//进入FrameBuffer驱动等待VSync中断到来
    if (ioctl(mFbFd, FBIO_WAITFORVSYNC, NULL) == -1)  {  
        ALOGE("fail to wait vsync , mFbFd:%d" , mFbFd);  
    }else{  
	  if(!mDev->procs || !mDev->procs->vsync){
	  	ALOGW("device procs or vsync is null procs:%x , vsync:%x", mDev->procs , mDev->procs->vsync);
	  	return true;
	  }
	  //调用VSync回调函数
      mDev->procs->vsync(mDev->procs, 0, systemTime(CLOCK_MONOTONIC));  
    }  
    return true;
}

在该线程运行过程中通过ioctl系统调用进入到fb驱动等待VSync中断,如果VSync中断到来,则ioctl函数从驱动中返回。同时如果注册了VSync回调处理函数,则调用该回调函数来响应VSync信号。在前面构造HWComposer对象时,我们已经注册了VSync中断回调函数为hook_vsync,该函数的实现如下:

void HWComposer::hook_vsync(struct hwc_procs* procs, int dpy, int64_t timestamp) {
    reinterpret_cast<cb_context *>(procs)->hwc->vsync(dpy, timestamp);
}

在该函数里调用HWComposer对象的vsync函数来出来响应VSync中断

void HWComposer::vsync(int dpy, int64_t timestamp) {
    ATRACE_INT("VSYNC", ++mVSyncCount&1);
    mEventHandler.onVSyncReceived(dpy, timestamp);
}

mEventHandler为DisplayHardware对象,这里又将VSync中断信号交给DisplayHardware对象处理,DisplayHardware继承于EventHandler类,并实现了该类的虚方法onVSyncReceived,这里调用DisplayHardware对象的onVSyncReceived函数来处理VSync中断信号。关于VSync信号的处理在稍后介绍,到此硬件产生VSync信号的过程就完成了。

2.软件模拟产生VSync信号过程

在构造HWComposer对象时,如果打开hwcomposer硬件抽象模块失败的话就使用软件方式模拟产生VSync信号,软件模拟产生过程就是通过一个线程间隔一段时间调用一次VSync回调函数,从而模拟VSync信号中断效果。首先创建一个专门用于产生VSync信号的线程:

HWComposer::VSyncThread::VSyncThread(HWComposer& hwc)
    : mHwc(hwc), mEnabled(false),
      mNextFakeVSync(0),
      mRefreshPeriod(hwc.mRefreshPeriod)
{
}

VSyncThread继承于RefBase类,该对象第一次强引用自动调用onFirstRef()函数,在该函数中启动线程

void HWComposer::VSyncThread::onFirstRef() {
    run("VSyncThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
}

VSyncThread线程的执行过程如下:

bool HWComposer::VSyncThread::threadLoop() {
    { // scope for lock
        Mutex::Autolock _l(mLock);
        while (!mEnabled) {//VSyncThread线程启动后并不立即产生VSync信号,只有通过调用setEnabled函数使能VSync信号后,该线程才往下执行,从而产生VSync信号
            mCondition.wait(mLock);
        }
    }
    const nsecs_t period = mRefreshPeriod;//VSync信号的产生间隔时间,屏幕刷新时间
    const nsecs_t now = systemTime(CLOCK_MONOTONIC);
    nsecs_t next_vsync = mNextFakeVSync;//下一次VSync信号产生时间
    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);
	//每隔屏幕刷新时间间隔调用一次onVSyncReceived函数
    if (err == 0) {
        mHwc.mEventHandler.onVSyncReceived(0, next_vsync);
    }
	//一次信号产生完成后,函数直接返回true,当threadLoop返回值为“真”时,它将被系统再一次调用,从而循环起来。
    return true;
}

mEnabled用于控制是否产生VSync信号。当希望关闭VSync信号发生源时,调用VSyncThread::setEnabled(false),否则传入true。mEnabled为false时,VSyncThread就处于等待状态,直到再次使能这个线程。

VSync产生步骤:

1)计算下一次产生VSync信号的时间

2)线程进入休眠

3)休眠时间到了后,发出VSync信号了,通知感兴趣的人

4)循环往复 屏幕刷新周期计算公式:mRefreshPeriod = nsecs_t(1e9 / mRefreshRate);如果屏幕刷新频率mRefreshRate为60Hz的话,mRefreshPeriod就差不多是16ms。mNextFakeVSync代表下一次产生信号的时间点,mNextFakeVSync代表的是下一次threadLoop需要用到的时间点,所以首先将next_vsync=mNextFakeVSync。然后计算产生下一次VSync信号需要睡眠的时间:sleep = (period – ((now – next_vsync) % period));

《Android VSync信号产生过程源码分析》

当休眠时间到了后,函数跳出while循环,表示VSync信号产生的时刻到了,这时就调用成员变量mEventHandler的onVSyncReceived函数来响应VSync信号,软件模拟产生VSync信号的间隔时间就是屏幕刷新周期。成员变量mEventHandler的类型为EventHandler,在HWComposer的构造函数中,该变量指向DisplayHardware对象,因此这里调用的是DisplayHardware对象的onVSyncReceived函数来处理VSync中断。这里可以看出,无论是硬件产生VSync还是软件模拟产生VSync信号,最终都是交给DisplayHardware对象处理:

void DisplayHardware::onVSyncReceived(int dpy, nsecs_t timestamp) {
    sp<VSyncHandler> handler;
    { // scope for the lock
        Mutex::Autolock _l(mLock);
        mLastHwVSync = timestamp;
        if (mVSyncHandler != NULL) {
            handler = mVSyncHandler.promote();
        }
    }

    if (handler != NULL) {
        handler->onVSyncReceived(dpy, timestamp);
    }
}

DisplayHardware的成员变量mVSyncHandler的类型为VSyncHandler,EventThread类继承于VSyncHandler类,在EventThread的onFirstRef()函数中,通过调用DisplayHardware的setVSyncHandler函数将构造的EventThread对象保存到DisplayHardware的成员变量mVSyncHandler中

void EventThread::onFirstRef() {
    mHw.setVSyncHandler(this);
    ...
}

因此DisplayHardware的成员变量mVSyncHandler实际指向的是EventThread对象。

void DisplayHardware::setVSyncHandler(const sp<VSyncHandler>& handler) {
    Mutex::Autolock _l(mLock);
    mVSyncHandler = handler;
}

由此可以看出,对VSync的处理又被DisplayHardware对象转交给了EventThread来完成。EventThread是一个线程类,该线程专门负责分发VSync信号。

void EventThread::onVSyncReceived(int, nsecs_t timestamp) {
    Mutex::Autolock _l(mLock);
    mVSyncTimestamp = timestamp;
    mCondition.broadcast();
}

VSync信号产生后,仅仅简单地打开线程互斥量,从而唤醒EventThread线程,让EventThread线程分发VSync信号到来事件给所有已经注册的连接。到此关于VSync信号的产生过程就介绍完了。

    原文作者:Android源码分析
    原文地址: https://blog.csdn.net/yangwen123/article/details/16969907
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞