Android Choreographer分析

Android在黄油计划中引入了三缓存+VSync的显示机制,简单概括就是屏幕每次刷新发送VSYNC信号,如果帧率为60fps,那么每隔16ms发送一个VSYNC信号,CPU加接收到VSYNC信号后放下手中的工作,立即处理显示相关的工作(layout, draw),然后将数据buffer交给GPU,GPU处理完和Display交换缓存数据buffer,Display每次都在拿到完整的一帧数据buffer后开始刷新工作,三缓存在GPU处理超时(>16ms)Jank时参与,提供一个空闲的缓存给CPU提前开始处理数据,避免下一帧因为同样的原因继续超时Jank。

其中Choreographer就是CPU用来接收VSYNC信号的对象。

一、Choreographer

Choreographer实例在ViewRootImpl构造器中被赋值给mChoreographer变量。

    public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
            WindowLayout windowLayout) {
      mChoreographer = Choreographer.getInstance();
    }

getInstance()从线程变量Choreographer.sThreadInstance获取实例对象,可知Choreographer为线程单例对象。

        private static final ThreadLocal<Choreographer> sThreadInstance =
                new ThreadLocal<Choreographer>() {
            @Override
            protected Choreographer initialValue() {
                Looper looper = Looper.myLooper();
                Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
                if (looper == Looper.getMainLooper()) {
                    mMainInstance = choreographer;
                }
                return choreographer;
            }
        };

查看Choreographer构造方法:

        private Choreographer(Looper looper, int vsyncSource) {
            mLooper = looper;
          	// 1.创建处理 frame 事件相关的handler。
            mHandler = new FrameHandler(looper);
          	// 2.创建mDisplayEventReceiver,VSYNC信号接收器。
            mDisplayEventReceiver = USE_VSYNC
                    ? new FrameDisplayEventReceiver(looper, vsyncSource)
                    : null;
    				// 3.记录最后绘制的时间
            mLastFrameTimeNanos = Long.MIN_VALUE;
          	// 4.记录每帧间隔: 1s / 屏幕刷新率
            mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
    				
          	// 5.初始化CallbackQueue,数组大小为 5。
            mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
            for (int i = 0; i <= CALLBACK_LAST; i++) {
                mCallbackQueues[i] = new CallbackQueue();
            }
            // b/68769804: For low FPS experiments.
            setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
        }

Choreographer的构造方法主要做了5件事:

  1. 创建处理 frame 事件相关的FrameHandler,looper是实例化ViewRootImpl的线程,一般是主线程。
  2. 创建mDisplayEventReceiver,VSYNC信号接收器。
  3. 记录最后绘制的时间mLastFrameTimeNanos。
  4. 设置屏幕刷新率mFrameIntervalNanos。
  5. 初始化CallbackQueue,数组大小为 5。CallbackQueue专门用来处理ViewRootImpl通过mChoreographer.postCallback()方法传递过来的回调事件,如ViewRootImpl在requestLayout()布局阶段:
    mChoreographer.postCallback(
    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    Choreographer 定义了以下5中回调类型:
    • CALLBACK_INPUT:输入事件。
    • CALLBACK_ANIMATION:动画事件。
    • CALLBACK_INSETS_ANIMATION:insets updates,INPUT和ANIMATION都会影响INSETS_ANIMATION,所以需要在这两之后执行。insets表示app和SystemUI,IME等系统组件重叠的部分。
    • CALLBACK_TRAVERSAL:layout, draw事件
    • CALLBACK_COMMIT:Commit callback,处理绘制完成后的操作。

接下来看下DisplayEventReceiver创建流程:

二、DisplayEventReceiver

    // Choreographer.java
    private final class FrameDisplayEventReceiver extends DisplayEventReceiver
            implements Runnable {
        private long mTimestampNanos;
        private int mFrame;
        private VsyncEventData mLastVsyncEventData = new VsyncEventData();
    
        public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
            super(looper, vsyncSource, 0);
        }
    
        @Override
        public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
                VsyncEventData vsyncEventData) {
            try {
                mFrame = frame;
                mLastVsyncEventData = vsyncEventData;
                Message msg = Message.obtain(mHandler, this);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
        }
    
        @Override
        public void run() {
            mHavePendingVsync = false;
            doFrame(mTimestampNanos, mFrame, mLastVsyncEventData);
        }
    }

FrameDisplayEventReceiver继承DisplayEventReceiver,并且实现了Runnable接口,覆盖了onVsync()方法,在接收到VSYNC信号后回调onVsync,通过mHandler发送消息回调自己的run()方法,调用doFrame(mTimestampNanos, mFrame, mLastVsyncEventData);处理业务逻辑。

查看父类DisplayEventReceiver如何实现接收VSYNC信号。

2.1 DisplayEventReceiver实例化

    //DisplayEventReceiver.java
    public DisplayEventReceiver(Looper looper, int vsyncSource, int eventRegistration) {
        mMessageQueue = looper.getQueue();
        mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
                vsyncSource, eventRegistration);
    }

调用nativeInit方法,参数vsyncSource变量值是VSYNC_SOURCE_APP,eventRegistration为0。

    // android_view_DisplayEventReceiver.cpp
    static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject messageQueueObj,
                            jint vsyncSource, jint eventRegistration) {
      	// 1.实例化NativeDisplayEventReceiver
        sp<NativeDisplayEventReceiver> receiver =
                new NativeDisplayEventReceiver(env, receiverWeak, messageQueue, vsyncSource,
                                               eventRegistration);
      	// 2.initialize
        status_t status = receiver->initialize();
    }
    
    class NativeDisplayEventReceiver : public DisplayEventDispatcher {
      NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak,
                                                           const sp<MessageQueue>& messageQueue,
                                                           jint vsyncSource, jint eventRegistration)
          : DisplayEventDispatcher(messageQueue->getLooper(),
                                   static_cast<ISurfaceComposer::VsyncSource>(vsyncSource),
                                   static_cast<ISurfaceComposer::EventRegistration>(eventRegistration)),
            mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
            mMessageQueue(messageQueue) {}
    }

nativeInit主要做了两件事:

  1. 实例化了NativeDisplayEventReceiver对象,NativeDisplayEventReceiver继承自父类DisplayEventDispatcher。
  2. 调用receiver->initialize()。

查看父类DisplayEventDispatcher。

2.1.1 DisplayEventDispatcher

    // DisplayEventDispatcher.cpp
    class DisplayEventDispatcher : public LooperCallback {
      
      DisplayEventReceiver mReceiver;
      
    	DisplayEventDispatcher::DisplayEventDispatcher(
            const sp<Looper>& looper, ISurfaceComposer::VsyncSource vsyncSource,
            ISurfaceComposer::EventRegistrationFlags eventRegistration)
          : mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false),
            mLastVsyncCount(0), mLastScheduleVsyncTime(0) {}
    
    	status_t DisplayEventDispatcher::initialize() {
        if (mLooper != nullptr) {
            int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);
        }
        return OK;
    	}
    }

DisplayEventDispatcher通过传递过来的参数实例化DisplayEventReceiver对象mReceiver,查看DisplayEventReceiver定义:

2.1.1.1 DisplayEventReceiver
    // DisplayEventReceiver.cpp
    DisplayEventReceiver::DisplayEventReceiver(
            ISurfaceComposer::VsyncSource vsyncSource,
            ISurfaceComposer::EventRegistrationFlags eventRegistration) {
        // 1.获取SurfaceFlinger对象
        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
        if (sf != nullptr) {
            // 2.surfaceflinger创建新的连接
            mEventConnection = sf->createDisplayEventConnection(vsyncSource, eventRegistration);
            if (mEventConnection != nullptr) {
                // 3.实例化BitTube对象,BitTube实例使用socket本地通信
                mDataChannel = std::make_unique<gui::BitTube>();
                // 4.BitTube实例关联IDisplayEventConnection
                const auto status = mEventConnection->stealReceiveChannel(mDataChannel.get());
                if (!status.isOk()) {
                    ALOGE("stealReceiveChannel failed: %s", status.toString8().c_str());
                    mInitError = std::make_optional<status_t>(status.transactionError());
                    mDataChannel.reset();
                    mEventConnection.clear();
                }
            }
        }
    }

DisplayEventReceiver构造方法中主要做了4件事:

  1. 通过ComposerService::getComposerService()获取SurfaceFlinger对象,getComposerService()方法在SurfaceComposerClient.cpp文件中实现,返回的对象是SurfaceFlinger:
        // SurfaceComposerClient.cpp
        void ComposerService::connectLocked() {
            const String16 name("SurfaceFlinger");
            while (getService(name, &mComposerService) != NO_ERROR) {
                usleep(250000);
            }
        }
    
  2. sf->createDisplayEventConnection创建新的连接,通过EventThread实例化新的EventThreadConnection对象,EventThread负责发送VSYNC信号给DisplayEventReceiver,EventThreadConnection持有变量gui::BitTube mChannel作为发送信号通道。
        // EventThread.h
        class EventThreadConnection : public gui::BnDisplayEventConnection {
        private:
            gui::BitTube mChannel GUARDED_BY(mLock);
        }
    
  3. 实例化BitTube对象,BitTube类表示DisplayEventReceiver和SurfaceFlinger具体通信通道的实现,内部使用socket本地通信实现,socketpair()创建两个互相连接本地通信(AF_UNIX)的socket,分别赋值给发送端BitTube.mSendFd,接收端BitTube.mReceiveFd:
    // BitTube.cpp
    void BitTube::init(size_t rcvbuf, size_t sndbuf) {
        int sockets[2];
        if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
            size_t size = DEFAULT_SOCKET_BUFFER_SIZE;
            setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
            setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));
            setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
            setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
            fcntl(sockets[0], F_SETFL, O_NONBLOCK);
            fcntl(sockets[1], F_SETFL, O_NONBLOCK);
            mReceiveFd.reset(sockets[0]);
            mSendFd.reset(sockets[1]);
        }
    }
    
  4. mEventConnection->stealReceiveChannel将刚创建好的BitTube对象传递给EventThreadConnection,至此VSYNC信号接收通道就创建好了。
    // EventThread.cpp
    binder::Status EventThreadConnection::stealReceiveChannel(gui::BitTube* outChannel) {
        outChannel->setReceiveFd(mChannel.moveReceiveFd());
        outChannel->setSendFd(base::unique_fd(dup(mChannel.getSendFd())));
        return binder::Status::ok();
    }
    

信号接收通道搭建好了,怎么接收处理信号呢?

2.2 receiver->initialize

回到2.1小节DisplayEventReceiver的nativeInit,在实例化NativeDisplayEventReceiver创建信号接收通道之后,调用receiver->initialize()定义信号接收处理操作。

NativeDisplayEventReceiver继承自DisplayEventDispatcher,initialize()在父类DisplayEventDispatcher中定义:

2.2.1 addFd

    // DisplayEventDispatcher.cpp
    status_t DisplayEventDispatcher::initialize() {
        if (mLooper != nullptr) {
            int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);
        }
        return OK;
    }

通过mLooper epoll机制监听socket,也就是2.1.1.1小节中BitTube.mReceiveFd,监听事件类型为Looper::EVENT_INPUT,mLooper是从Choreographer构造方法一直传递过来的参数赋值的,也就是实例化ViewRootImpl对象的线程。

当socket存在Looper::EVENT_INPUT时唤醒looper,回调handleEvent()方法:

2.2.2 handleEvent

    // DisplayEventDispatcher.cpp
    int DisplayEventDispatcher::handleEvent(int, int events, void*) {
        // Drain all pending events, keep the last vsync.
        nsecs_t vsyncTimestamp;
        PhysicalDisplayId vsyncDisplayId;
        uint32_t vsyncCount;
        VsyncEventData vsyncEventData;
        if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
            ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64
                  ", displayId=%s, count=%d, vsyncId=%" PRId64,
                  this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
                  vsyncEventData.preferredVsyncId());
            mWaitingForVsync = false;
            mLastVsyncCount = vsyncCount;
            dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
        }
        if (mWaitingForVsync) {
            const nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
            const nsecs_t vsyncScheduleDelay = currentTime - mLastScheduleVsyncTime;
            if (vsyncScheduleDelay > WAITING_FOR_VSYNC_TIMEOUT) {
                ALOGW("Vsync time out! vsyncScheduleDelay=%" PRId64 "ms", ns2ms(vsyncScheduleDelay));
                mWaitingForVsync = false;
                dispatchVsync(currentTime, vsyncDisplayId /* displayId is not used */,
                              ++mLastVsyncCount, vsyncEventData /* empty data */);
            }
        }
        return 1; // keep the callback
    }

调用processPendingEvents()封装vsyncEventData等参数,分发VSYNC事件dispatchVsync()。

2.2.3 dispatchVsync

dispatchVsync方法在子类NativeDisplayEventReceiver实现:

    void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,
                                                   uint32_t count, VsyncEventData vsyncEventData) {
        JNIEnv* env = AndroidRuntime::getJNIEnv();
        ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
        if (receiverObj.get()) {
            jobject javaVsyncEventData = createJavaVsyncEventData(env, vsyncEventData);
            env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,
                                timestamp, displayId.value, count, javaVsyncEventData);
        }
        mMessageQueue->raiseAndClearException(env, "dispatchVsync");
    }

封装Java层的vsyncEventData对象,调用Java对象DisplayEventReceiver的dispatchVsync方法。

    // DisplayEventReceiver.java
    private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) {
        onVsync(timestampNanos, physicalDisplayId, frame);
    }

第2小节提到过,Choreographer中FrameDisplayEventReceiver类继承自DisplayEventReceiver,自此VSYNC信号传递到了Choreographer。

Choreographer在接收到VSYNC信号后执行doFrame()方法。

2.2.4 doFrame

    void doFrame(long frameTimeNanos, int frame) {
        // 计算丢帧数,startNanos当前时间,frameTimeNanos信号发送时间,jitterNanos也就是信号发送到处理的时间间隔。
        final long jitterNanos = startNanos - frameTimeNanos;
        if (jitterNanos >= mFrameIntervalNanos) {
            final long skippedFrames = jitterNanos / mFrameIntervalNanos;
        }
        // 更新帧信息mFrameInfo
        mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
        // 处理 INPUT回调
        mFrameInfo.markInputHandlingStart();
        doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
        // 处理 ANIMATION回调
        mFrameInfo.markAnimationsStart();
        doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
        doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
        // 处理 TRAVERSAL回调,layout,draw
        mFrameInfo.markPerformTraversalsStart();
        doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
        // 处理 帧被绘制完成后的操作
        doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
    }

doFrame更新当前帧信息到mFrameInfo变量,轮流处理回调方法:INPUT(输入事件回调)–>ANIMATION(动画事件回调)–>TRAVERSAL(布局,绘制回调)–>COMMIT(帧被绘制完成后操作)。

一般回调事件都由ViewRootImpl发出,对于处理布局和绘制的CALLBACK_TRAVERSAL消息,为了在接收到VSYNC信号后立即处理显示数据buff,不被线程中其他事件给耽搁,在postCallback前先发送同步消息屏障postSyncBarrier到looper,优先处理异步的CALLBACK_TRAVERSAL消息,在消息被处理后移除looper中的同步消息屏障。

VSYNC信号每隔16ms发送一次,Choreographer每次都要相应VSYNC信号执行doFrame吗?答案是不会,只有在DisplayEventReceiver.scheduleVsync()后才会接收处理VSYNC,比如ViewRootImpl中调用mChoreographer.postCallback():

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

dueTime判断callback是否需要立即执行,立即执行调用scheduleFrameLocked(now),通过DisplayEventReceiver.scheduleVsync()请求VSYNC信号,SurfaceFlinger在接收到请求信号后发出VSYNC信号,处理完请求后Choreographer不会接收到VSYNC,也就是说一个静止不刷新的界面是不需要接收VSYNC信号刷新的。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值