快速理解SurfaceFlinger 三、开机动画(1)

3.1 BootAnimation 结构

源码路径:frameworks/base/cmds/bootanimation

├── Android.mk
├── audioplay.cpp
├── audioplay.h
├── BootAnimation.cpp
├── BootAnimation.h
├── bootanimation_main.cpp
├── bootanim.rc
└── FORMAT.md

Android.mk

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
    bootanimation_main.cpp \  #入口在这里
    audioplay.cpp \
    BootAnimation.cpp #主要方法

LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES

LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code

LOCAL_C_INCLUDES += \
    external/tinyalsa/include \
    frameworks/wilhelm/include

LOCAL_SHARED_LIBRARIES := \
    libcutils \
    liblog \
    libandroidfw \
    libutils \
    libbinder \
    libui \
    libskia \
    libEGL \
    libGLESv1_CM \
    libgui \
    libOpenSLES \
    libtinyalsa

LOCAL_MODULE:= bootanimation

LOCAL_INIT_RC := bootanim.rc

ifdef TARGET_32_BIT_SURFACEFLINGER
LOCAL_32_BIT_ONLY := true
endif

include $(BUILD_EXECUTABLE) #编译为可执行程序

运行入口在bootanimation_main.cpp

int main()
{
    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);

    char value[PROPERTY_VALUE_MAX];
    property_get("debug.sf.nobootanimation", value, "0");
    int noBootAnimation = atoi(value);
    ALOGI_IF(noBootAnimation,  "boot animation disabled");
    if (!noBootAnimation) {

        sp proc(ProcessState::self());
        ProcessState::self()->startThreadPool();

        // create the boot animation object
        sp boot = new BootAnimation();

        IPCThreadState::self()->joinThreadPool();

    }
    return 0;
}

sp proc(ProcessState::self()); 作用是打开binder驱动,与内核建立内存映射关系。

ProcessState::self()->startThreadPool(); 启动binder主线程,可以与binder Service通讯。还可以有其他binder线程,这些线程并不是由动画进程启动,是由binder驱动间接创建启动。

IPCThreadState::self()->joinThreadPool(); 使线程进入循环,等待消息,处理数据,完成与binder驱动数据处理。相当于Bp(代理)作用。

3.2 BootAnimation 的启动

BootAnimation 并未在init.rc中配置为开机自启动,那么它到底是如何启动?

3.2.1 再回到SurfaceFlinger初始化过程来看,

void SurfaceFlinger::init() {
    ALOGI(  "SurfaceFlinger's main thread ready to run. "
            "Initializing graphics H/W...");

    { // Autolock scope
        Mutex::Autolock _l(mStateLock);

        // initialize EGL for the default display
        mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
        eglInitialize(mEGLDisplay, NULL, NULL);

        // start the EventThread
        sp vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
                vsyncPhaseOffsetNs, true, "app");
        mEventThread = new EventThread(vsyncSrc, *this);
        sp sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
                sfVsyncPhaseOffsetNs, true, "sf");
        mSFEventThread = new EventThread(sfVsyncSrc, *this);
        mEventQueue.setEventThread(mSFEventThread);

        // set SFEventThread to SCHED_FIFO to minimize jitter
        struct sched_param param = {0};
        param.sched_priority = 2;
        if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) {
            ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
        }

        // Get a RenderEngine for the given display / config (can't fail)
        mRenderEngine = RenderEngine::create(mEGLDisplay,
                HAL_PIXEL_FORMAT_RGBA_8888);
    }

    // Drop the state lock while we initialize the hardware composer. We drop
    // the lock because on creation, it will call back into SurfaceFlinger to
    // initialize the primary display.
    mHwc = new HWComposer(this);
    mHwc->setEventHandler(static_cast(this));

    Mutex::Autolock _l(mStateLock);

    // retrieve the EGL context that was selected/created
    mEGLContext = mRenderEngine->getEGLContext();

    LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
            "couldn't create EGLContext");

    // make the GLContext current so that we can create textures when creating
    // Layers (which may happens before we render something)
    getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);

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

    // initialize our drawing state
    mDrawingState = mCurrentState;

    // set initial conditions (e.g. unblank default device)
    initializeDisplays();

    mRenderEngine->primeCache();

    // start boot animation
    startBootAnim();//这里启动动画进程

    ALOGV("Done initializing");
}

可以看到SurfaceFlinger::init()启动动画进程,在之前还有很多初始化工作。

可以判断出这些初始化工作与动画显示关系很大。
 

        // initialize EGL for the default display
        mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
        eglInitialize(mEGLDisplay, NULL, NULL);

EGL可以理解为Open GL与本地窗口的中间件,为Open GL传递上下文、绘图目标、Buffer等配置属性等。这样Open GL可以做到平台无关化。

mEGLDisplay 即 EGLDisplay实例,表示系统显示ID。

EGL_DEFAULT_DISPLAY表示获取默认显示。

eglInitialize(),后两个参数表示传递版本号,这里忽略版本号。

 

        // start the EventThread
        sp vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
                vsyncPhaseOffsetNs, true, "app");
        mEventThread = new EventThread(vsyncSrc, *this);
        sp sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
                sfVsyncPhaseOffsetNs, true, "sf");
        mSFEventThread = new EventThread(sfVsyncSrc, *this);
        mEventQueue.setEventThread(mSFEventThread);

vsyncSrc 用于应用监控Vsync信号,sfVsyncSrc内部监控Vsync信号。

Vsync保证CPUGPU运行的时间在一个周期内,目的是消除Jank

如何做到监听Vsync信号

DispSyncSource

class DispSyncSource : public VSyncSource, private DispSync::Callback {
public:
    DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
        const char* name) :
            mName(name),
            mValue(0),
            mTraceVsync(traceVsync),
            mVsyncOnLabel(String8::format("VsyncOn-%s", name)),
            mVsyncEventLabel(String8::format("VSYNC-%s", name)),
            mDispSync(dispSync),
            mCallbackMutex(),
            mCallback(),
            mVsyncMutex(),
            mPhaseOffset(phaseOffset),
            mEnabled(false) {}

    virtual ~DispSyncSource() {}

    virtual void setVSyncEnabled(bool enable) {//使能接口,可以关闭Vsync
        Mutex::Autolock lock(mVsyncMutex);
        if (enable) {
            status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
                    static_cast(this));
            if (err != NO_ERROR) {
                ALOGE("error registering vsync callback: %s (%d)",
                        strerror(-err), err);
            }
            //ATRACE_INT(mVsyncOnLabel.string(), 1);
        } else {
            status_t err = mDispSync->removeEventListener(
                    static_cast(this));
            if (err != NO_ERROR) {
                ALOGE("error unregistering vsync callback: %s (%d)",
                        strerror(-err), err);
            }
            //ATRACE_INT(mVsyncOnLabel.string(), 0);
        }
        mEnabled = enable;
    }
//....
private:
    virtual void onDispSyncEvent(nsecs_t when) {//检测到vsync信号到来
        sp callback;
        {
            Mutex::Autolock lock(mCallbackMutex);
            callback = mCallback;

            if (mTraceVsync) {
                mValue = (mValue + 1) % 2;
                ATRACE_INT(mVsyncEventLabel.string(), mValue);
            }
        }

        if (callback != NULL) {
            callback->onVSyncEvent(when);//具体怎么做,在callback里定义
        }
    }

//...
};


总体的作用是利用Vsync信号即时间定时,Vsync可以由硬件产生也可以由软件模拟。在规定时间到后,刷新界面。

mRenderEngine = RenderEngine::create(mEGLDisplay,HAL_PIXEL_FORMAT_RGBA_8888);//建立渲染引擎

3.2.2 下面介绍 SurfaceFlinger init() 最后一部分代码

    // Drop the state lock while we initialize the hardware composer. We drop
    // the lock because on creation, it will call back into SurfaceFlinger to
    // initialize the primary display.
    mHwc = new HWComposer(this);//硬件图层合成器对象
    mHwc->setEventHandler(static_cast(this));

    Mutex::Autolock _l(mStateLock);

    // retrieve the EGL context that was selected/created
    mEGLContext = mRenderEngine->getEGLContext();

    LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
            "couldn't create EGLContext");

    // make the GLContext current so that we can create textures when creating
    // Layers (which may happens before we render something)
    getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);

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

    // initialize our drawing state
    mDrawingState = mCurrentState;

    // set initial conditions (e.g. unblank default device)
    initializeDisplays();

    mRenderEngine->primeCache();

    // start boot animation
    startBootAnim();

    ALOGV("Done initializing");

HWComposer 有两个作用

1.由硬件图层合成器提供Vsync信号

2.针对所有的surface(各个需要显示的界面)会有对应的Layer,HWC将对可以合成的(overlay)图层将交给HWC HAL层处理。根据SOC的差异,HWC HAL会使用GPU 2D core 或者GPU 3D core。最终数据写入Display Framebuffer,完成显示。HWC不能处理的图层,将使用EGL处理即直接交给GPU处理。

总体流程是根据硬件特性,图层合成由硬件图层合成器或者GPU处理。

回到代码:

    mHwc = new HWComposer(this);//硬件图层合成器对象
    mHwc->setEventHandler(static_cast(this));//SurfaceFlinger可监听Vsync信号

    // retrieve the EGL context that was selected/created
    mEGLContext = mRenderEngine->getEGLContext();//GEL 上下文

    LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
            "couldn't create EGLContext");

    // make the GLContext current so that we can create textures when creating
    // Layers (which may happens before we render something)
    getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);//绑定上下文和Surface

//此线程用于控制Vsync使能开关,入口在EventControlThread::setVsyncEnabled(bool enabled) 

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

可以看下线程的具体实现:frameworks/native/services/surfaceflinger$ vim EventControlThread.cpp

bool EventControlThread::threadLoop() {
    Mutex::Autolock lock(mMutex);

    bool vsyncEnabled = mVsyncEnabled;

#ifdef USE_HWC2
    mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled);
#else
    mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC,
            mVsyncEnabled);
#endif

    while (true) {
        status_t err = mCond.wait(mMutex);
        if (err != NO_ERROR) {
            ALOGE("error waiting for new events: %s (%d)",
                strerror(-err), err);
            return false;
        }

        if (vsyncEnabled != mVsyncEnabled) {
#ifdef USE_HWC2
            mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled);
#else
            mFlinger->eventControl(HWC_DISPLAY_PRIMARY,
                    SurfaceFlinger::EVENT_VSYNC, mVsyncEnabled);
#endif
            vsyncEnabled = mVsyncEnabled;
        }
    }

    return false;
}

 

    // initialize our drawing state
    mDrawingState = mCurrentState;

    // set initial conditions (e.g. unblank default device)
    initializeDisplays();

void SurfaceFlinger::initializeDisplays() {
    class MessageScreenInitialized : public MessageBase {
        SurfaceFlinger* flinger;
    public:
        MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { }
        virtual bool handler() {
            flinger->onInitializeDisplays();
            return true;
        }
    };
    sp msg = new MessageScreenInitialized(this);
    postMessageAsync(msg);  // we may be called from main thread, use async message
}

经过消息处理,最终还是会回到SurfaceFlinger::onInitializeDisplays

void SurfaceFlinger::onInitializeDisplays() {
    // reset screen orientation and use primary layer stack
    Vector state;
    Vector displays;
    DisplayState d;
    d.what = DisplayState::eDisplayProjectionChanged |
             DisplayState::eLayerStackChanged;
    d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY];
    d.layerStack = 0;
    d.orientation = DisplayState::eOrientationDefault;
    d.frame.makeInvalid();
    d.viewport.makeInvalid();
    d.width = 0;
    d.height = 0;
    displays.add(d);
    setTransactionState(state, displays, 0);
    setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL);

    const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
    const nsecs_t period = activeConfig->getVsyncPeriod();
    mAnimFrameTracker.setDisplayRefreshPeriod(period);
}

Display还原,重置屏幕方向并使用主层堆栈。

mRenderEngine->primeCache();//着色器缓存进行初始化

    // start boot animation
    startBootAnim();//开始启动动画

至此SurfaceFlinger已完成动画包括界面显示的初始化工作,总体上是使能Vsync、初始化HWC HAL、初始化EGL。

SurfaceFlinger属于服务端,动画是客户端,客户端必然会与服务端通讯才能完成画面的显示。

 

你可能感兴趣的:(显示系统)