美文网首页AndroidAndroid Stability
界面显示_视图Choreographer控制

界面显示_视图Choreographer控制

作者: gczxbb | 来源:发表于2018-03-02 14:32 被阅读148次

    Choreographer_舞蹈编导

    为什么叫舞蹈编导,因为舞蹈是由节奏的,节奏是每个点位动作的快慢控制,跳舞时节奏很重要,编舞者控制节奏。视图刷新也是如此,不是说你想刷就能刷,一切要按照底层信号要求的节奏来。

    理解屏幕刷新频率

    刷新频率:每秒钟刷新屏幕的次数,从缓存中取出每一帧,显示到屏幕上的速度。
    帧率:GPU/CPU生成每一帧画面图像,存入缓存中的速度。
    一般情况下帧率是大于刷新频率的,每个设备的刷新频率固定,与硬件相关,若帧率是刷新率的两倍,两张图像画面,只能有一个现实到屏幕上,也就是说生产画面的速度要大于显示画面的速度。典型的生产者-消费者模式。
    屏幕刷新过程:从左到右刷新一行,然后垂直刷新,再一行..,直到屏幕刷新完毕。每一次刷新,都是这一个过程,刷新一次后,中间有一个期间,刷新率太高,每秒60帧左右,人眼无法感知。
    tearing:若帧率大于刷新率,会导致在刷新前一帧还未开始时,缓存已经被新一帧覆盖一部分,那么在刷新前一帧时,现显示的一部分是新一帧内容。会导致画面前后帧上下重叠。这种情况技术上称之tearing,画面撕裂的意思。
    解决方案:增加缓存到两个缓存,CPU生成帧存入一个缓存A,屏幕取出帧存入另一个缓存B,解决了一个缓存导致生产者与消费者不同步的问题。增加Vsync同步信号,负责调度将A缓存拷贝到B缓存,显示取出的就是一个完整帧的画面。Vsync信号在一帧刷新完的中间期间产生,A到B的复制(交换地址即可),进入下一次刷新,并通知生产者gpu/cpu继续生产帧,只有收到Vsync信号,生产者才会生产帧。因此,可使帧率与刷新率保持同步,消耗一次才生成一次。
    掉帧:若Vsync信号发出时,A缓存正在被生产者锁住生产,gpu绘制生产帧时间超过信号发出时刻一点,此时不会复制。导致B缓存仍是老帧,下一次周期与前一次刷新相同的帧。当gpu生产结束后,此时刷新老数据的刷新周期中,还没有Vsync信号,则gpu空闲
    掉帧解决方案:再增加一个缓存到三个缓存。当有缓存锁住时复制他前面的上一次被锁住的另一个缓存。

    Android平台提供两种信号,一种是硬件信号,另一种是软件信号,由SurfaceFlinger进程的一个线程定时发出,硬件信号由硬件发出。
    App进程若要通过gpu实现图像绘制,需要在接收到Vsync信号的条件下进行,因此,App进程访问SurfaceFlinger进程获取这个信号,再进行gpu绘制。

    Choreographer就是负责获取Vsync同步信号并控制App线程(主要是主线程绘图)完成图像绘制的类。


    Choreographer单例

    在Android系统中主要是主线程负责UI绘制,其他线程也可以绘制,如SurfaceView,这里以主线程UI绘制进行介绍。

    每个线程中保存一个Choreographer实例对象。

    Choreographer#sThreadInstance静态对象。

    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类型,在线程中初始化变量时,创建Choreographer对象,绑定主线程Looper。

    每个窗体旗下ViewRootImpl均使用同一个Choregrapher对象,它承担控制大部分视图绘制节奏的工作。

    安排一次遍历

    一次遍历,就是完成一个树形视图的绘制过程,遍历视图树的每一个节点。
    ViewRootImpl#scheduleTraversals方法。

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

    每当ViewRootImpl安排一次遍历scheduleTraversals,设置标志位mTraversalScheduled,防止多次安排。发送同步栅栏。当执行遍历doTraversal或主动取消遍历unscheduleTraversals时,关掉标志位。取消同步栅栏。
    委托Choreographer安排遍历,请求信号。

    Choreographer#postCallback分析

    Choreographer#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) {//没有延迟,以当前时间安排帧。
                scheduleFrameLocked(now);
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
    }
    

    Choreographer#postCallback的功能是向回调请求数组中存入一个对应类型的记录,该纪录封装回调任务,当前时间,等待信号安排一帧绘制。CallbackQueue数组,数组元素是CallbackQueue对象,内部包含指向CallbackRecord链表的头指针。四种callbackType类型:CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL、CALLBACK_COMMIT。每一种callbackType类型代表数组的一个索引。

    CallbackQueue数组.png

    CallbackQueue#addCallbackLocked方法,创建一个CallbackRecord对象,封装dueTime执行时间(当前时间+延迟),任务action和token。将CallbackRecord插入链表,按照dueTime时间排序决定插入位置,dueTime小的位于链表的前面。
    这里只关注CALLBACK_TRAVERSAL类型回调任务TraversalRunnable,当收到Vsync信号时,触发执行doTraversal方法

    没有延迟,立即安排,触发Choreographer#scheduleFrameLocked方法。若有延迟,等待delayMillis时间,在特定时刻dueTime利用Choreographer内部FrameHandler发送消息。
    Choreographer#FrameHandler#handleMessage方法

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

    FrameHandler处理延迟发送的CALLBACK,触发doScheduleCallback方法。
    Choreographer#doScheduleCallback方法。

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

    有延迟时,当到达时间dueTime,在handleMessage方法开始执行,最终实现一次安排,与没有延迟时一样,触发Choreographer#scheduleFrameLocked方法。
    注意,在经过一段时间的延迟,中间有不确定性,增加两个条件判断。

    • 若mFrameScheduled标志,表示此时已经有过一次安排,请求一次有回复在doFrame处重置标志。这时,不再安排。
    • 获取当前时间now,当链表头结点的dueTime比now大,表示当时以(now + delayMillis)插入的CallbackRecord节点已经不在链表中了,否则在(now + delayMillis)时刻执行获取的当前时间一定会大于或等于now,链表每个元素的dueTime都大于now,或者头节点是空,这种情况下不再安排。

    Choreographer#scheduleFrameLocked分析

    Choreographer#scheduleFrameLocked方法

    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);
            }
        }
    }
    

    now参数是执行该方法前获取的当前时间。执行时设置mFrameScheduled标志,底层回调后才会重置此标志。
    USE_VSYNC默认是true,若当前线程Looper与Choreographer的Looper一致,即与Choreographer所在线程一样,触发Choreographer#scheduleVsyncLocked方法,通过注册的接收器JNI访问底层请求垂直同步信号。
    当前线程与Choreographer所在线程不同,通过FrameHandler发送消息,FrameHandler负责处理Choreographer线程事务消息。

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

    在doScheduleVsync方法中触发Choreographer#scheduleVsyncLocked方法
    Choreographer#postCallback流程图如下所示。

    Choreographer#postCallback流程 .png

    显示事件接收器

    Java层DisplayEventReceiver分析

    Choreographer#scheduleVsyncLocked方法

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

    Choreographer#mDisplayEventReceiver是FrameDisplayEventReceiver类型,它在Choreographer构造方法初始化,继承DisplayEventReceiver
    Java#DisplayEventReceiver构造方法。

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

    DisplayEventReceiver创建时,绑定Choreographer线程的消息队列JNI#nativeInit方法初始化底层对象,创建一个DisplayEventReceiver的弱引用,与消息队列一起,传入底层。
    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());
    }
    

    nativeInit方法主要工作

    • 根据Java层MQ获取Native层消息队列,Choreographer线程消息队列。
    • 创建JNI层接收器NativeDisplayEventReceiver,它继承LooperCallback,将mReceiverPtr指针返回给Java层DisplayEventReceiver对象。封装Java层弱引用receiverWeak、Native层消息队列、Native层DisplayEventReceiver对象。

    NativeDisplayEventReceiver#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监听Native层对象DisplayEventReceiver中BitTube的mReceiverFd描述符。监听一旦接收到消息,在Looper中将触发handleEvent回调方法

    Java层DisplayEventReceiver通过JNI调用实现帧画面的显示控制,主要三个任务:底层初始化(nativeInit),发起请求(scheduleVsync),实现回调(dispatchVsync)。

    Native层DisplayEventReceiver分析

    Native#DisplayEventReceive构造方法

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

    在DisplayEventReceiver构造方法,初始化两个重要对象的指针。

    • mEventConnection,IDisplayEventConnection类型。
    • mDataChannel,BitTube类型。

    IDisplayEventConnection负责真正向底层发起请求,涉及与SurfaceFlinger进程通信,它定义了与SurfaceFlinger进程通信的业务逻辑接口。

    IDisplayEventConnection接口业务层方法
    requestNextVsync:请求下一次垂直同步信号。
    setVsyncRate:设置垂直同步帧率。
    getDataChannel:获取通信管道。

    sf是App进程ISurfaceComposer业务代理,业务对象在SurfaceFlinger进程,SurfaceFlinger对象,继承BnSurfaceComposer。
    ISurfaceComposer业务进程通信如图所示。

    ISurfaceComposer业务进程通信.png
    App进程:
    ISurfaceComposer代理#createDisplayEventConnection方法,返回IDisplayEventConnection业务代理mEventConnection,它继承BpDisplayEventConnection。

    App进程利用mEventConnection三个业务方法请求SurfaceFlinger进程服务。

    SurfaceFlinger进程:
    SurfaceFlinger#createDisplayEventConnection方法,创建IDisplayEventConnection业务对象Connection,继承BnDisplayEventConnection。在与App进程通信时,Parcal#writeStrongBinder与readStrongBinder实现Binder对象传输,内核红黑树创建服务与引用节点,在App进程端创建业务代理BpDisplayEventConnection。
    SurfaceFlinger进程#createDisplayEventConnection方法。

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

    EventThread#createEventConnection方法。

    sp<EventThread::Connection> EventThread::createEventConnection() const {
        //在创建前会向EventThread注册该连接,加入到mDisplayEventConnections中。
        return new Connection(const_cast<EventThread*>(this));
    }
    

    创建Connection对象,它是EventThread内部类。
    Connection#构造方法。

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

    在Connection构造方法,构建数据通道BitTube,BitTub内部一对Socket描述符,提供读写方法用于数据通讯。
    IDisplayEventConnection业务进程通信如图所示。

    IDisplayEventConnection业务进程通信.png
    BitTube分析

    BitTube#构造方法

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

    BitTube#init方法

    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发送与接收描述符,提供读写数据的管道功能。Tube的意思是管,BitTube即字节管道。socket缓存4MmSendFd用于写入,写入后,mReceivedFd接收端能读取,mReceiveFd用于接收。

    App进程:
    通过IDisplayEventConnection#getDataChannel方法获取BitTube,SurfaceFlinger进程利用writeDupFileDescriptor写入mReceivedFd描述符,App进程从Parcel中读取描述符,创建BitTube对象,封装mReceivedFd描述符
    BpDisplayEventConnection#getDataChannel方法

    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方法负责FileDescriptor类型读写存储。
    BitTube#构造方法(带Parcel参数)。

    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));
        }
    }
    

    综上:BitTube通过socketpair建立一对匿名已经连接套接字mReceiveFd与mSendFd,实现SurfaceFlinger与App进程的双向通信管道。在App进程中,有mReceiveFd描述符,监听描述符来自SurfaceFlinger进程mSendFd端的消息。

    Choreographer接收器与SurfaceFlinger通信的架构图如下。 Choreographer接收器与SurfaceFlinger通信流程架构图.png

    Java层DisplayEventReceiver请求下一次垂直同步信号的过程

    流程图
    DisplayEventReceiver请求下一次信号的流程.png

    JNI#nativeScheduleVsync方法。

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

    根据Java层receiverPtr指针,获取NativeDisplayEventReceiver对象。
    DisplayEventReceiver#scheduleVsync方法。

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

    DisplayEventReceiver#requestNextVsync方法。

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

    跨进程IDisplayEventConnection业务#requestNextVsync方法,请求SurfaceFlinger进程提供服务,与SurfaceFlinger进程的Connection服务通信,Connection实现IDisplayEventConnection业务。Connection代表与App的连接,而不是SurfaceFlinger主线程的连接。
    Connection#requestNextVsync方法。

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

    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进程的一个循环线程mEventThread,该线程在waitForEvent处等待,被唤醒后可利用Connection发送事件。

    SurfaceFlinger循环线程EventThread

    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,每个都发送event
            const sp<Connection>& conn(signalConnections[i]);
            status_t err = conn->postEvent(event);//写入的内容是Event类型
            if (err == -EAGAIN || err == -EWOULDBLOCK) {
                ...
            } else if (err < 0) {
                removeDisplayEventConnection(signalConnections[i]);
            }
        }
        return true;
    }
    

    在threadLoop循环中,唯一的工作是waitForEvent等待VSYNC信号,当信号发生时,发送给BitTube#mSendFd句柄。注意:SurfaceFlinger有两个EventThread线程,运行在各自的循环中。

    SurfaceFlinger绘制延迟线程mEventThread发送消息

    遍历收到信号的Connection,触发Connection#postEvent方法,调用DisplayEventReceiver#sendEvents方法,利用Connection内部BitTube即mChannel的write方法发送数据到mSendFd句柄,App进程的mReceiveFd就能收到消息。
    Connection#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);
     }
    

    利用数据通道BitTube发送消息,write方法。
    DisplayEventReceiver#sendEvents方法

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

    dataChannel是BitTube对象,保存在Connection内部。 BitTube#sendObjects触发BitTube#write方法,即dataChannel的write方法,向mSendFd写入数据,App进程mReceiveFd可收到数据,实现SurfaceFlinger进程到App进程的数据传输。

    App进程Choreographer线程Looper与SurfaceFlinger主线程Looper都在监听各自的mReceiveFd,等待数据到来。

    App进程Choreographer线程监听到消息

    App进程,mReceiveFd收到消息后,Choreographer线程Looper触发LooperCallback#handleEvent方法,即NativeDisplayEventReceiver#handleEvent方法,调用NativeDisplayEventReceiver#dispatchVsync方法。
    NativeDisplayEventReceiver#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);
        }
        ...
    }
    

    env#CallVoidMethod触发Java层DisplayEventReceiver对象的dispatchVsync方法。
    Java#DisplayEventReceiver#dispatchVsync方法。

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

    在Choreographer类,FrameDisplayEventReceiver重写onVsync方法,onVsync由Choreographer线程执行。

    onVsync流程图如下所示。 FrameDisplayEventReceiver#onVsync方法执行流程图.png

    FrameDisplayEventReceiver#onVsync方法

    @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);
    }
    

    特定时刻发送消息,FrameDisplayEventReceiver实现Runnable。


    SurfaceFlinger主线程消息队列与描述符监听

    SurfaceFlinger#init方法初始化两个EventThread线程,与主线程通信的是mSFEventThread线程

    SurfaceFlinger#init方法。

    void SurfaceFlinger::init() {
        ...
        sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
                vsyncPhaseOffsetNs, true, "app");
        mEventThread = new EventThread(vsyncSrc);
        sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
                sfVsyncPhaseOffsetNs, true, "sf");
        mSFEventThread = new EventThread(sfVsyncSrc);
        mEventQueue.setEventThread(mSFEventThread);
        ...
    }
    
    • mEventThread线程:负责处理App进程的绘制请求事件,具体请求交由Connection服务处理
    • mSFEventThread线程:与SurfaceFlinger主线程通信,发送消息。
    • MessageQueue:SurfaceFlinger主线程消息队列。
    SurfaceFlinger#init初始化EventThread线程如图所示。 SurfaceFlinger#init初始化EventThread线程.png

    EventThread#onFirstRef方法,在EventThread构造方法执行后调用。

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

    EventThread#run启动线程,循环执行EventThread#threadLoop方法。
    MessageQueue结构图如下所示。

    SurfaceFlinger的MessageQueue结构图.png SurfaceFlinger主线程触发MessageQueue#init方法,初始化主线程消息队列,初始化主线程Looper与Handler。
    SurfaceFlinger#onFirstRef方法。
    void SurfaceFlinger::onFirstRef(){
        mEventQueue.init(this);
    }
    

    MessageQueue#init方法。

    void MessageQueue::init(const sp<SurfaceFlinger>& flinger) {
        mFlinger = flinger;
        mLooper = new Looper(true);
        mHandler = new Handler(*this);
    }
    

    MessageQueue#setEventThread方法。

    void MessageQueue::setEventThread(const sp<EventThread>& eventThread) {
        mEventThread = eventThread;
        mEvents = eventThread->createEventConnection();
        mEventTube = mEvents->getDataChannel();
        mLooper->addFd(mEventTube->getFd(), 0, Looper::EVENT_INPUT,
                MessageQueue::cb_eventReceiver, this);
    }
    

    MessageQueue#setEventThread方法主要功能是SurfaceFlinger主线程Looper监听mReceiveFd描述符。

    setEventThread方法负责设置EventThread,创建Connection与BitTube,Looper监听BitTube#mReceiveFd描述符,cb_eventReceiver是回调方法。

    信号源DispSyncSource

    SurfaceFlinger#init方法,创建两个DispSyncSource信号源,一个用于App进程绘制请求,另一个用于SurfaceFlinger合成。

    EventThread构造方法传入DispSyncSource,DispSyncSource内部是相同的DispSync对象
    EventThread与DispSyncSource结构关系图如下所示。

    EventThread与DispSyncSource的结构图.png EventThread继承Thread,实现VSyncSource#Callback接口,#onVSyncEvent方法。DispSyncSource#Callback设置成EventThread。
    DispSync#构造方法。
    DispSync::DispSync() :
            mRefreshSkipCount(0),
            mThread(new DispSyncThread()) {
        mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
        reset();
        beginResync();  
    }
    

    DispSync创建时,启动一个DispSyncThread线程。

    DispSyncThread线程的主要工作是不断向DispSyncSource信号源发送vsync信号。

    DispSyncThread线程产生信号,执行DispSyncSource#onDispSyncEvent方法,触发Callback#onVSyncEvent方法,而EventThread正是Callback,因此,程序执行EventThread#onVSyncEvent方法。在此处,mSFEventThread线程被唤醒broadcast。
    EventThread#onVSyncEvent方法。

    void EventThread::onVSyncEvent(nsecs_t timestamp) {
        Mutex::Autolock _l(mLock);
        //mVSyncEvent是一个Event的数组
        mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
        mVSyncEvent[0].header.id = 0;
        //接收的vsync信号是一个时间戳,每个之间间隔mPeriod
        mVSyncEvent[0].header.timestamp = timestamp; 
        mVSyncEvent[0].vsync.count++;//每次事件都加1
        mCondition.broadcast();//唤醒waitForEvent
    }
    

    mSFEventThread线程被broadcast唤醒后,以同样的方法向mSendFd句柄发送数据,SurfaceFlinger主线程Looper监听mReceiveFd收到消息,触发cb_eventReceiver回调方法。
    MessageQueue#cb_eventReceiver方法

    int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
        //当在EventThread线程,向mSendFd发送时,Looper监听到并处理事件
        MessageQueue* queue = reinterpret_cast<MessageQueue *>(data);
        return queue->eventReceiver(fd, events);
    }
    

    MessageQueue#eventReceiver方法。

    int MessageQueue::eventReceiver(int /*fd*/, int /*events*/) {
        ssize_t n;
        DisplayEventReceiver::Event buffer[8];
        while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) {
            for (int i=0 ; i<n ; i++) {//每个buffer元素是DisplayEventReceiver::Event
                if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {//判断类型是vsync信号
    #if INVALIDATE_ON_VSYNC//获取的event保存在buffer中
                    mHandler->dispatchInvalidate();//MQ内部Handler处理
    #else
                    mHandler->dispatchRefresh();
    #endif
                    break;
                }
            }
        }
        return 1;
    }
    

    DisplayEventReceiver#getEvents方法,利用BitTube#recvObjects方法接收消息,接收mReceiveFd获取的消息。读取BitTube#mReceiveFd描述符的数据,在SurfaceFlinger主线程处理。mEventTube是MQ内部BitTube对象。
    DisplayEventReceiver#getEvents方法。

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

    任重而道远

    相关文章

      网友评论

        本文标题:界面显示_视图Choreographer控制

        本文链接:https://www.haomeiwen.com/subject/rzdaxftx.html