界面顯示_視圖Choreographer控制


為什么叫舞蹈編導(dǎo),因為舞蹈是由節(jié)奏的,節(jié)奏是每個點位動作的快慢控制,跳舞時節(jié)奏很重要,編舞者控制節(jié)奏。視圖刷新也是如此,不是說你想刷就能刷,一切要按照底層信號要求的節(jié)奏來。

理解屏幕刷新頻率

刷新頻率:每秒鐘刷新屏幕的次數(shù),從緩存中取出每一幀,顯示到屏幕上的速度。
幀率:GPU/CPU生成每一幀畫面圖像,存入緩存中的速度。
一般情況下幀率是大于刷新頻率的,每個設(shè)備的刷新頻率固定,與硬件相關(guān),若幀率是刷新率的兩倍,兩張圖像畫面,只能有一個現(xiàn)實到屏幕上,也就是說生產(chǎn)畫面的速度要大于顯示畫面的速度。典型的生產(chǎn)者-消費者模式。
屏幕刷新過程:從左到右刷新一行,然后垂直刷新,再一行..,直到屏幕刷新完畢。每一次刷新,都是這一個過程,刷新一次后,中間有一個期間,刷新率太高,每秒60幀左右,人眼無法感知。
tearing:若幀率大于刷新率,會導(dǎo)致在刷新前一幀還未開始時,緩存已經(jīng)被新一幀覆蓋一部分,那么在刷新前一幀時,現(xiàn)顯示的一部分是新一幀內(nèi)容。會導(dǎo)致畫面前后幀上下重疊。這種情況技術(shù)上稱之tearing,畫面撕裂的意思。
解決方案:增加緩存到兩個緩存,CPU生成幀存入一個緩存A,屏幕取出幀存入另一個緩存B,解決了一個緩存導(dǎo)致生產(chǎn)者與消費者不同步的問題。增加Vsync同步信號,負(fù)責(zé)調(diào)度將A緩存拷貝到B緩存,顯示取出的就是一個完整幀的畫面。Vsync信號在一幀刷新完的中間期間產(chǎn)生,A到B的復(fù)制(交換地址即可),進(jìn)入下一次刷新,并通知生產(chǎn)者gpu/cpu繼續(xù)生產(chǎn)幀,只有收到Vsync信號,生產(chǎn)者才會生產(chǎn)幀。因此,可使幀率與刷新率保持同步,消耗一次才生成一次。
掉幀:若Vsync信號發(fā)出時,A緩存正在被生產(chǎn)者鎖住生產(chǎn),gpu繪制生產(chǎn)幀時間超過信號發(fā)出時刻一點,此時不會復(fù)制。導(dǎo)致B緩存仍是老幀,下一次周期與前一次刷新相同的幀。當(dāng)gpu生產(chǎn)結(jié)束后,此時刷新老數(shù)據(jù)的刷新周期中,還沒有Vsync信號,則gpu空閑。
掉幀解決方案:再增加一個緩存到三個緩存。當(dāng)有緩存鎖住時復(fù)制他前面的上一次被鎖住的另一個緩存。

Android平臺提供兩種信號,一種是硬件信號,另一種是軟件信號,由SurfaceFlinger進(jìn)程的一個線程定時發(fā)出,硬件信號由硬件發(fā)出。
App進(jìn)程若要通過gpu實現(xiàn)圖像繪制,需要在接收到Vsync信號的條件下進(jìn)行,因此,App進(jìn)程訪問SurfaceFlinger進(jìn)程獲取這個信號,再進(jìn)行g(shù)pu繪制。

Choreographer就是負(fù)責(zé)獲取Vsync同步信號并控制App線程(主線程)完成圖像繪制的類。

在Android系統(tǒng)中主要是主線程進(jìn)行UI繪制,其他線程也可以繪制,比如SurfaceView,本文以主線程UI繪制進(jìn)行介紹。

每個線程中保存一個Choreographer實例對象。

private static final ThreadLocal<Choreographer> sThreadInstance =
            new ThreadLocal<Choreographer>() {
    @Override
    protected Choreographer initialValue() {
        Looper looper = Looper.myLooper();
        if (looper == null) {
            //拋出異常。
        }
        return new Choreographer(looper);
    }
};

線程本地存儲ThreadLocal變量,Choreographer類型,在主線程中初始化變量時,創(chuàng)建Choreographer對象,綁定主線程Looper。

同一個App的每個窗體旗下ViewRootImpl使用的同一個Choregrapher對象,他控制者整個App中大部分視圖的繪制節(jié)奏。


安排一次繪制

一次繪制,就是完成一個樹形視圖的測量、布局、繪制的過程,遍歷視圖樹的每一個節(jié)點,當(dāng)然,可以根據(jù)條件判斷,省略掉其中一個或幾個環(huán)節(jié),比如,只刷新繪制,不測量和布局。

void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        ...
    }
}

ViewRootImpl對象的scheduleTraversals安排一次繪制,安排后,將設(shè)置標(biāo)志位mTraversalScheduled,防止多次安排,發(fā)送同步柵欄。
當(dāng)執(zhí)行繪制doTraversal方法或unscheduleTraversals方法主動取消繪制時,關(guān)掉標(biāo)志位,取消同步柵欄。委托Choreographer安排繪制,請求信號。
postCallbackDelayedInternal方法,調(diào)用postCallbackDelayedInternal。

private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
    synchronized (mLock) {
        final long now = SystemClock.uptimeMillis();
        final long dueTime = now + delayMillis;
        mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
        if (dueTime <= now) {//沒有延遲,以當(dāng)前時間安排幀。
            scheduleFrameLocked(now);
        } else {
            Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
            msg.arg1 = callbackType;
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, dueTime);
        }
    }
}

該postCallback方法向回調(diào)請求數(shù)組CallbackQueues中存入一個對應(yīng)類型的記錄CallbackRecord,該紀(jì)錄封裝回調(diào)任務(wù)、當(dāng)前時間,等待信號安排一幀繪制。數(shù)組元素是CallbackQueue,內(nèi)部包含指向CallbackRecord鏈表的頭指針。四種callbackType類型CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL、CALLBACK_COMMIT。每一種callbackType類型代表數(shù)組的一個索引。
CallbackQueue數(shù)組.jpg

CallbackQueue的addCallbackLocked方法,創(chuàng)建一個CallbackRecord,封裝dueTime執(zhí)行時間(當(dāng)前時間+延遲),任務(wù)action和token。插入鏈表,按照dueTime時間排序,dueTime時間小的在鏈表頭部。
本文只關(guān)注CALLBACK_TRAVERSAL類型和TraversalRunnable回調(diào)任務(wù),當(dāng)收到Vsync信號時,將觸發(fā)任務(wù)的doTraversal方法。

沒有延遲,scheduleFrameLocked方法立即安排。
有延遲,等待delayMillis時間,在特定時間dueTime,通過Choreographer內(nèi)部FrameHandler發(fā)送消息。

@Override
public void handleMessage(Message msg) {
    switch (msg.what) {
        ...
        case MSG_DO_SCHEDULE_CALLBACK:
            doScheduleCallback(msg.arg1);
            break;
    }
}

FrameHandler處理延遲發(fā)送的CALLBACK,觸發(fā)doScheduleCallback方法。

void doScheduleCallback(int callbackType) {
    synchronized (mLock) {
        if (!mFrameScheduled) {
            final long now = SystemClock.uptimeMillis();
            if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
                scheduleFrameLocked(now);
            }
        }
    }
}

有延遲時,當(dāng)?shù)竭_(dá)時間dueTime,在handleMessage方法開始執(zhí)行,最終實現(xiàn)一次繪制,和沒有延遲時一樣,觸發(fā)scheduleFrameLocked方法。注意,經(jīng)過一段時間的延遲,中間有不確定性,增加兩個條件判斷。
mFrameScheduled標(biāo)志,表示此時已經(jīng)有過一次scheduled,請求一次有回復(fù)在doFrame處重置標(biāo)志。這時,不再scheduled。
當(dāng)鏈表頭結(jié)點的dueTime比當(dāng)前時間now大,表示當(dāng)時以(now + delayMillis)插入的CallbackRecord節(jié)點已經(jīng)不在鏈表中了,否則在(now + delayMillis)時刻執(zhí)行獲取的當(dāng)前時間一定會<=now,鏈表每個元素的dueTime都大于now,或者頭節(jié)點是空,這種情況下不再scheduled。

scheduleFrameLocked方法,schedule一次具體的幀繪制。

private void scheduleFrameLocked(long now) {
    if (!mFrameScheduled) {
        mFrameScheduled = true;
        if (USE_VSYNC) {
            if (isRunningOnLooperThreadLocked()) {
                scheduleVsyncLocked();
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtFrontOfQueue(msg);
            }
        } else {
            final long nextFrameTime = Math.max(
                    mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
            ...   
            Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, nextFrameTime);
        }
    }
}

入?yún)ow是執(zhí)行該方法前獲取的當(dāng)前時間,設(shè)置mFrameScheduled標(biāo)志,底層回調(diào)后重置標(biāo)志。
默認(rèn)USE_VSYNC,當(dāng)前線程和Choreographer綁定線程一致,直接調(diào)用Choreographer的scheduleVsyncLocked方法,線程不同,通過FrameHandler發(fā)送消息,在Choreographer線程處理事務(wù)消息。

@Override
public void handleMessage(Message msg) {
    switch (msg.what) {
        ...
        case MSG_DO_SCHEDULE_VSYNC:
            doScheduleVsync();
            break;
    }
}

同樣,在doScheduleVsync會調(diào)用scheduleVsyncLocked方法。postCallback方法流程圖。

Choreographer的postCallback方法流程.jpg

最終統(tǒng)一調(diào)用到scheduleVsyncLocked方法,它通過注冊的接收器JNI方法訪問底層,請求垂直同步信號。


顯示事件接收器基礎(chǔ)架構(gòu)

scheduleVsyncLocked方法,通過DisplayEventReceiver的scheduleVsync實現(xiàn)請求同步信號。

private void scheduleVsyncLocked() {
    mDisplayEventReceiver.scheduleVsync();
}

它是FrameDisplayEventReceiver類型,繼承DisplayEventReceiver,在編舞者的構(gòu)造方法中初始化,Java層DisplayEventReceiver構(gòu)造方法。

public DisplayEventReceiver(Looper looper) {
    ..//Looper是空拋異常
    mMessageQueue = looper.getQueue();
    mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue);
}

DisplayEventReceiver會綁定Choreographer線程消息隊列。創(chuàng)建一個弱引用,和消息隊列一起,JNI#nativeInit方法初始化傳入底層。

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject messageQueueObj) {
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    ...
    sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
            receiverWeak, messageQueue);
    status_t status = receiver->initialize();
    ...
    receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); 
    return reinterpret_cast<jlong>(receiver.get());
}

根據(jù)Java層MQ獲取底層消息隊列,創(chuàng)建一個NativeDisplayEventReceiver,JNI層接收器,繼承LooperCallback,將mReceiverPtr指針返回Java層。JNI層接收器封裝Java層弱引用receiverWeak、底層消息隊列,底層接收器。
JNI層接收器的initialize初始化方法。

status_t NativeDisplayEventReceiver::initialize() {
    status_t result = mReceiver.initCheck();
    ...
    int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
            this, NULL);
    return OK;
}

向Choreographer線程Looper監(jiān)聽底層DisplayEventReceiver對象中BitTube的mReceiverFd描述符。一旦接收到消息,將觸發(fā)Looper的handleEvent回調(diào)方法。

底層DisplayEventReceive的構(gòu)造方法。

DisplayEventReceiver::DisplayEventReceiver() {
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != NULL) {
        mEventConnection = sf->createDisplayEventConnection();
        if (mEventConnection != NULL) {
            mDataChannel = mEventConnection->getDataChannel();
        }
    }
}

初始化兩個重要指針,IDisplayEventConnection類型(mEventConnection)和BitTube類型(mDataChannel)。
IDisplayEventConnection負(fù)責(zé)和SurfaceFlinger進(jìn)程通信,真正向底層發(fā)起請求,定義了進(jìn)程通信的業(yè)務(wù)接口,IDisplayEventConnection業(yè)務(wù)層接口方法。

上面代碼中sf是App進(jìn)程ISurfaceComposer業(yè)務(wù)代理,真實的業(yè)務(wù)對象是SurfaceFlinger對象,繼承BnSurfaceComposer,在SurfaceFlinger進(jìn)程。ISurfaceComposer業(yè)務(wù)進(jìn)程通信。

ISurfaceComposer業(yè)務(wù)進(jìn)程通信.png

在App進(jìn)程,ISurfaceComposer代理的createDisplayEventConnection方法,返回IDisplayEventConnection業(yè)務(wù)代理,繼承BpDisplayEventConnection,也就是mEventConnection。然后,App進(jìn)程就能通過IDisplayEventConnection的三個業(yè)務(wù)方法,requestNextVsync方法,請求下一次垂直同步信號。setVsyncRate方法,設(shè)置垂直同步幀率。getDataChannel方法,獲取通信管道。

在SurfaceFlinger進(jìn)程,SurfaceFlinger對象的createDisplayEventConnection方法,創(chuàng)建IDisplayEventConnection業(yè)務(wù)真實對象Connection,繼承BnDisplayEventConnection。和App進(jìn)程通信時,參數(shù)是Binder類型的,Parcal的writeStrongBinder和readStrongBinder方法可以實現(xiàn)Binder對象的傳輸,內(nèi)核紅黑樹創(chuàng)建服務(wù)和引用節(jié)點,App進(jìn)程創(chuàng)建出BpDisplayEventConnection業(yè)務(wù)代理。
SurfaceFlinger進(jìn)程的createDisplayEventConnection方法。

sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
    return mEventThread->createEventConnection();
}

sp<EventThread::Connection> EventThread::createEventConnection() const {
    //在創(chuàng)建前會向EventThread注冊該連接,加入到mDisplayEventConnections中。
    return new Connection(const_cast<EventThread*>(this));
}

創(chuàng)建Connection對象,它是EventThread內(nèi)部類,該類的構(gòu)造方法。

EventThread::Connection::Connection(const sp<EventThread>& eventThread)
    : count(-1), mEventThread(eventThread), mChannel(new BitTube())
{
}

創(chuàng)建數(shù)據(jù)通道BitTube,內(nèi)部一對Socket描述符,提供讀寫方法,用于數(shù)據(jù)通訊。
IDisplayEventConnection業(yè)務(wù)進(jìn)程通信圖。

IDisplayEventConnection業(yè)務(wù)進(jìn)程通信.png

BitTube的構(gòu)造方法和初始化方法。

BitTube::BitTube()
    : mSendFd(-1), mReceiveFd(-1){
    init(DEFAULT_SOCKET_BUFFER_SIZE, DEFAULT_SOCKET_BUFFER_SIZE);
}

void BitTube::init(size_t rcvbuf, size_t sndbuf) {
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
        ...
        mReceiveFd = sockets[0];
        mSendFd = sockets[1];
    } else {
        mReceiveFd = -errno;
    }
}

初始化一對socket發(fā)送/接收描述符,提供讀/寫數(shù)據(jù)的管道功能。Tube的意思是管,BitTube即字節(jié)管道。socket緩存4M,mSendFd用于寫入,mReceiveFd用于接收,寫入后,接收端mReceivedFd能讀取。

App進(jìn)程,通過BpDisplayEventConnection的getDataChannel方法獲取通信管道,SurfaceFlinger進(jìn)程,通過writeDupFileDescriptor寫入mReceivedFd描述符,App進(jìn)程從Parcel中讀取,創(chuàng)建新BitTube對象封裝mReceivedFd描述符。

virtual sp<BitTube> getDataChannel() const {
    Parcel data, reply;
    data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor());
    remote()->transact(GET_DATA_CHANNEL, data, &reply);
    return new BitTube(reply);
}

Parcel的writeDupFileDescriptor和readFileDescriptor方法負(fù)責(zé)FileDescriptor類型讀寫存儲。BitTube的構(gòu)造方法(帶Parcel參數(shù))。

BitTube::BitTube(const Parcel& data)
    : mSendFd(-1), mReceiveFd(-1) {
    mReceiveFd = dup(data.readFileDescriptor());
    if (mReceiveFd < 0) {
        mReceiveFd = -errno;
        ALOGE("BitTube(Parcel): can't dup filedescriptor (%s)",
                strerror(-mReceiveFd));
    }
}

Choreographer接收器與SurfaceFlinger通信的架構(gòu)圖。
Choreographer接收器與SurfaceFlinger通信的架構(gòu)圖.jpg

請求垂直同步信號流程

Java層DisplayEventReceiver請求一次垂直同步信號的過程。
DisplayEventReceiver請求同步信號的流程.jpg

前兩個方法已經(jīng)看過了,直接看一下JNI#nativeScheduleVsync方法。

static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
    sp<NativeDisplayEventReceiver> receiver =
            reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
    status_t status = receiver->scheduleVsync();
    ...
}

根據(jù)Java層receiverPtr指針,獲取JNI層的NativeDisplayEventReceiver對象

status_t NativeDisplayEventReceiver::scheduleVsync() {
    if (!mWaitingForVsync) {
        ...
        processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount);
        status_t status = mReceiver.requestNextVsync();
        ...
        mWaitingForVsync = true;
    }
    return OK;
}

JNI層接收器封裝底層DisplayEventReceiver,調(diào)用requestNextVsync方法。

status_t DisplayEventReceiver::requestNextVsync() {
    if (mEventConnection != NULL) {
        mEventConnection->requestNextVsync();
        return NO_ERROR;
    }
    return NO_INIT;
}

底層DisplayEventReceiver,內(nèi)部兩個重要指針已經(jīng)介紹過。
IDisplayEventConnection業(yè)務(wù)#requestNextVsync方法,和SurfaceFlinger進(jìn)程通信,該進(jìn)程實現(xiàn)業(yè)務(wù)接口的是Connection對象。sf進(jìn)程Connection的requestNextVsync方法。

void EventThread::Connection::requestNextVsync() {
    mEventThread->requestNextVsync(this);
}

Connection內(nèi)部EventThread的requestNextVsync方法。

void EventThread::requestNextVsync(
        const sp<EventThread::Connection>& connection) {
    Mutex::Autolock _l(mLock);
    if (connection->count < 0) {
        connection->count = 0;
        mCondition.broadcast();
    }
}

通知mCondition條件,broadcast方法喚醒SurfaceFlinger進(jìn)程的一個循環(huán)線程mEventThread,該線程在waitForEvent處等待,被喚醒后可利用Connection發(fā)送事件。

SurfaceFlinger循環(huán)線程EventThread的threadLoop方法

bool EventThread::threadLoop() {
    DisplayEventReceiver::Event event;
    Vector< sp<EventThread::Connection> > signalConnections;
    signalConnections = waitForEvent(&event);//等待事件,等待得到的事件保存在event指針處

    const size_t count = signalConnections.size();
    for (size_t i=0 ; i<count ; i++) {//遍歷有信號的Connection,每個都發(fā)送event
        const sp<Connection>& conn(signalConnections[i]);
        status_t err = conn->postEvent(event);//寫入的內(nèi)容是Event類型
        if (err == -EAGAIN || err == -EWOULDBLOCK) {
            ...
        } else if (err < 0) {
            removeDisplayEventConnection(signalConnections[i]);
        }
    }
    return true;
}

該循環(huán)線程唯一的工作是在waitForEvent方法處等待VSYNC信號,當(dāng)信號發(fā)生時,發(fā)送給BitTube#mSendFd句柄。
注意,SurfaceFlinger有兩個EventThread線程,運行在各自的循環(huán)中。

收到信號時,遍歷收到信號的Connection,調(diào)用它的postEvent方法。

status_t EventThread::Connection::postEvent(
        const DisplayEventReceiver::Event& event) {
    ssize_t size = DisplayEventReceiver::sendEvents(mChannel, &event, 1);
    return size < 0 ? status_t(size) : status_t(NO_ERROR);
 }

DisplayEventReceiver的sendEvents方法。

ssize_t DisplayEventReceiver::sendEvents(const sp<BitTube>& dataChannel,
        Event const* events, size_t count) {
    return BitTube::sendObjects(dataChannel, events, count);
}

利用Connection內(nèi)部BitTube(即mChannel),BitTube的sendObjects將觸發(fā)BitTube#write方法,向mSendFd寫入數(shù)據(jù),App進(jìn)程mReceiveFd可收到數(shù)據(jù),實現(xiàn)SurfaceFlinger進(jìn)程到App進(jìn)程的數(shù)據(jù)傳輸。

App進(jìn)程Choreographer線程監(jiān)聽消息

在接收器架構(gòu)中,JNI層的NativeDisplayEventReceiver繼承LooperCallback,在初始化addFd時,將本身加入Looper回調(diào),當(dāng)App進(jìn)程的mReceiveFd描述符收到消息后,Choreographer線程的底層Looper將觸發(fā)LooperCallback的handleEvent方法。也就是NativeDisplayEventReceiver的handleEvent方法。
調(diào)用dispatchVsync方法。

void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t 
          id, uint32_t count) {
    JNIEnv* env = AndroidRuntime::getJNIEnv();
    ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
    if (receiverObj.get()) {
        env->CallVoidMethod(receiverObj.get(),
                gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);
    }
    ...
}

CallVoidMethod方法將調(diào)用Java層DisplayEventReceiver對象dispatchVsync方法。

private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) {
    onVsync(timestampNanos, builtInDisplayId, frame);
}

在Choreographer類,接收器就是FrameDisplayEventReceiver類型,它重寫onVsync方法,被底層Looper監(jiān)聽到的,在Choreographer線程執(zhí)行。onVsync方法的流程圖。

FrameDisplayEventReceiver的onVsync方法執(zhí)行流程圖.jpg

@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
    ...
    long now = System.nanoTime();
    if (timestampNanos > now) {
        timestampNanos = now;
    }
    ...
    mTimestampNanos = timestampNanos;
    mFrame = frame;
    Message msg = Message.obtain(mHandler, this);
    msg.setAsynchronous(true);
    mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}

特定的時刻發(fā)送消息,Message攜帶任務(wù),而FrameDisplayEventReceiver實現(xiàn)Runnable,因此,最后在特定的時刻運行FrameDisplayEventReceiver的run方法。

@Override
public void run() {
    mHavePendingVsync = false;
    doFrame(mTimestampNanos, mFrame);
}

觸發(fā)doFrame方法。

void doFrame(long frameTimeNanos, int frame) {
    final long startNanos;
    synchronized (mLock) {
        if (!mFrameScheduled) {
            return; // no work to do
        }
        long intendedFrameTimeNanos = frameTimeNanos;
        startNanos = System.nanoTime();
        final long jitterNanos = startNanos - frameTimeNanos;
        if (jitterNanos >= mFrameIntervalNanos) {
            final long skippedFrames = jitterNanos / mFrameIntervalNanos;
            if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
                Log.i(TAG, "Skipped " + skippedFrames + " frames!  "
                        + "The application may be doing too much work on its main thread.");
            }
            final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
            if (DEBUG_JANK) {
                Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
                        + "which is more than the frame interval of "
                        + (mFrameIntervalNanos * 0.000001f) + " ms!  "
                        + "Skipping " + skippedFrames + " frames and setting frame "
                        + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
            }
            frameTimeNanos = startNanos - lastFrameOffset;
        }

        if (frameTimeNanos < mLastFrameTimeNanos) {
            if (DEBUG_JANK) {
                Log.d(TAG, "Frame time appears to be going backwards.  May be due to a "
                        + "previously skipped frame.  Waiting for next vsync.");
            }
            scheduleVsyncLocked();
            return;
        }

        mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
        mFrameScheduled = false;
        mLastFrameTimeNanos = frameTimeNanos;
    }

    try {
        mFrameInfo.markInputHandlingStart();
        doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);

        mFrameInfo.markAnimationsStart();
        doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);

        mFrameInfo.markPerformTraversalsStart();
        doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
        doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
    } finally {
    }
}

恢復(fù)mFrameScheduled標(biāo)志,入?yún)⒋砩弦粋€幀的時間,如果當(dāng)前時間已經(jīng)>=frameTimeNanos一個間隔,表示發(fā)生了跳幀,根據(jù)時間差值/幀間隔計算跳過幀數(shù),重置frameTimeNanos為不發(fā)生挑幀時,最近的一個幀時間點。最后,設(shè)置mLastFrameTimeNanos值,記錄上一幀的時間。
下面的事情就是回調(diào)處理每個類型的Callbacks,觸發(fā)CallbackRecord的run方法,CallbackRecord封裝了任務(wù)action。對于CALLBACK_TRAVERSAL類型,最終會回調(diào)到ViewRootImpl#TraversalRunnable的run方法。

final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        doTraversal();
    }
}

ViewRootImpl的doTraversal方法,實現(xiàn)一次遍歷繪制。


總結(jié)

1,Java層DisplayEventReceiver通過JNI調(diào)用,根據(jù)底層垂直同步信號請求,實現(xiàn)幀畫面的顯示控制,在需要繪制時,發(fā)起請求,當(dāng)?shù)讓影l(fā)出信號時,同步回調(diào)到上層執(zhí)行。底層初始化(nativeInit),發(fā)起請求(scheduleVsync),實現(xiàn)回調(diào)(dispatchVsync)。
2,請求信號時,利用Binder機(jī)制同surfaceflinger進(jìn)程通信,在surfaceflinger進(jìn)程的業(yè)務(wù)對象是Connection,代表和App的一個連接。
3,底層通知上層是通過socketpair建立一對匿名已經(jīng)連接套接字mReceiveFd與mSendFd,實現(xiàn)SurfaceFlinger與App進(jìn)程的雙向通信管道。在App進(jìn)程中,有mReceiveFd描述符,監(jiān)聽描述符來自SurfaceFlinger進(jìn)程mSendFd端的消息。
4,App進(jìn)程Choreographer線程Looper負(fù)責(zé)監(jiān)聽來自mReceiveFd描述符。


任重而道遠(yuǎn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容