表现框架之Choreographer

藏宝库编辑 2024-9-4 09:31:08 94 0 来自 中国
Android为了提供一个稳固的帧率输出机制,让软件层和硬件层可以以共同的频率一起工作,引入了 Vsync + TripleBuffer + Choreographer 的刷帧机制。
引入Choreographer

Choreographer 的引入,重要是共同 Vsync ,给上层 App 的渲染提供一个稳固的 Message 处置处罚的时机,也就是 Vsync 到来的时间 ,会唤醒Choreographer 来做 App 的绘制利用。
Choreographer作用

Choreographer 扮演 Android 渲染链路中承上启下的脚色。
承上:负责接收和处置处罚 App 的各种更新消息和回调,比及 Vsync 到来的时间同一处置处罚。比如会合处置处罚 Input(重要是 Input 事故的处置处罚) 、Animation(动画相干)、Traversal(包括 measure、layout、draw 等利用) ,判断卡顿掉帧环境,纪录 CallBack 耗时等
启下:负责哀求和接收 Vsync 信号,通过申请和接收vsync来驱动app刷新。
简朴明白,Choreographer + SurfaceFlinger + Vsync + TripleBuffer这一套从上到下的机制,包管了 Android App 可以以一个稳固的帧率运行,减少帧率颠簸带来的不适感。下面从源码一探究竟Choreographer 的工作逻辑。
Choreographer初始化

文件:frameworks/base/core/java/android/view/ViewRootImpl.javapublic ViewRootImpl(Context context, Display display, IWindowSession session,            boolean useSfChoreographer) {       ...       // ViewRootImpl 初始化的时间创建Choreographer        mChoreographer = useSfChoreographer                ? Choreographer.getSfInstance() : Choreographer.getInstance();       ...}文件:frameworks/base/core/java/android/view/Choreographer.java// Thread local storage for the choreographer.    private static final ThreadLocal<Choreographer> sThreadInstance =            new ThreadLocal<Choreographer>() {        @Override        protected Choreographer initialValue() {           // 获取当火线程的looper            Looper looper = Looper.myLooper();            if (looper == null) {                throw new IllegalStateException("The current thread must have a looper!");            }           // 创建Choreographer 对象,source范例为app            Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);            if (looper == Looper.getMainLooper()) {                mMainInstance = choreographer;            }            return choreographer;        }    };  private Choreographer(Looper looper, int vsyncSource) {        mLooper = looper;        // 初始化 FrameHandler        mHandler = new FrameHandler(looper);       // 初始化 DisplayEventReceiver        mDisplayEventReceiver = USE_VSYNC                ? new FrameDisplayEventReceiver(looper, vsyncSource)                : null;        mLastFrameTimeNanos = Long.MIN_VALUE;        mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());        // 初始化 CallbacksQueues,存放5种范例的callback        mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];        for (int i = 0; i <= CALLBACK_LAST; i++) {            mCallbackQueues = new CallbackQueue();        }        // b/68769804: For low FPS experiments.        setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));    }     // 实现handleMessage 方法    private final class FrameHandler extends Handler {        public FrameHandler(Looper looper) {            super(looper);        }        @Override        public void handleMessage(Message msg) {            switch (msg.what) {                case MSG_DO_FRAME:                    doFrame(System.nanoTime(), 0);                    break;                case MSG_DO_SCHEDULE_VSYNC:                    doScheduleVsync();                    break;                case MSG_DO_SCHEDULE_CALLBACK:                    doScheduleCallback(msg.arg1);                    break;            }        }    }我们把FrameDisplayEventReceiver 的初始化单独拿出来分析。
FrameDisplayEventReceiver初始化

文件:frameworks/base/core/java/android/view/Choreographer.java private final class FrameDisplayEventReceiver extends DisplayEventReceiver            implements Runnable {        private boolean mHavePendingVsync;        private long mTimestampNanos;        private int mFrame;        public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {           // 实行DisplayEventReceiver 的初始化            super(looper, vsyncSource, CONFIG_CHANGED_EVENT_SUPPRESS);        }文件:frameworks/base/core/java/android/view/DisplayEventReceiver.java public DisplayEventReceiver(Looper looper, int vsyncSource, int configChanged) {        if (looper == null) {            throw new IllegalArgumentException("looper must not be null");        }        mMessageQueue = looper.getQueue();        // 通过jni调到native层        mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,                vsyncSource, configChanged);        mCloseGuard.open("dispose");    }文件:frameworks/base/core/jni/android_view_DisplayEventReceiver.cppstatic jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,        jobject messageQueueObj, jint vsyncSource, jint configChanged) {    ...     // NativeDisplayEventReceiver 继承 DisplayEventDispatcher, 实行DisplayEventDispatcher的初始化    sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,            receiverWeak, messageQueue, vsyncSource, configChanged);    // 实行DisplayEventDispatcher::initialize    status_t status = receiver->initialize();    ...}文件:frameworks/native/libs/gui/DisplayEventDispatcher.cppDisplayEventDispatcher:isplayEventDispatcher(const sp<Looper>& looper,                                               ISurfaceComposer::VsyncSource vsyncSource,                                               ISurfaceComposer::ConfigChanged configChanged)      : mLooper(looper), mReceiver(vsyncSource, configChanged), mWaitingForVsync(false) {    ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);}status_t DisplayEventDispatcher::initialize() {    status_t result = mReceiver.initCheck();    if (result) {        ALOGW("Failed to initialize display event receiver, status=%d", result);        return result;    }    if (mLooper != nullptr) {        // 添加mReceiveFd 监控,同Surfaceflinger的Message添加fd类似,区别是looper在差异的线程,回调的方法也不一样        int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);        if (rc < 0) {            return UNKNOWN_ERROR;        }    }    return OK;}这里告急的方法是mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL), 添加mReceiveFd 监控。那什么时间唤醒底层的loop等候呢?就是实行EventThread:: dispatchEvent,会对mSendFd进行write利用,这里接纳socket通讯,当监听到mReceiveFd 有变瞎搅时,进行唤醒,从而实行回调函数handleEvent。
文件:system/core/libutils/Looper.cppint Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {...   Request request;   request.fd = fd;   request.ident = ident;   request.events = events;   request.seq = mNextRequestSeq++;   request.callback = callback;   request.data = data;...   if (requestIndex < 0) {            // 添加mReceiveFd 进行监控            int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, fd, &eventItem);            if (epollResult < 0) {                ALOGE("Error adding epoll events for fd %d: %s", fd, strerror(errno));                return -1;            }            mRequests.add(fd, request);...}int Looper::pollInner(int timeoutMillis) {...int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);...for (size_t i = 0; i < mResponses.size(); i++) {      ...            // 实行addFd 时参加的回调函数            int callbackResult = response.request.callback->handleEvent(fd, events, data);      ...    return result;}文件:frameworks/native/libs/gui/DisplayEventDispatcher.cpp int DisplayEventDispatcher::handleEvent(int, int events, void*) {    if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {        ALOGE("Display event receiver pipe was closed or an error occurred.  "              "events=0x%x",              events);        return 0; // remove the callback    }    if (!(events & Looper::EVENT_INPUT)) {        ALOGW("Received spurious callback for unhandled poll event.  "              "events=0x%x",              events);        return 1; // keep the callback    }    // Drain all pending events, keep the last vsync.    nsecs_t vsyncTimestamp;    PhysicalDisplayId vsyncDisplayId;    uint32_t vsyncCount;    if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {        ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64              ", displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%d",              this, ns2ms(vsyncTimestamp), vsyncDisplayId, vsyncCount);        mWaitingForVsync = false;        dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);    }    return 1; // keep the callback}到这里初始化完成,总结下做了哪些变乱:

  • 初始化DisplayEventDispatcher,添加mReceiveFd进行监控,为vsync事故到来做回调预备
  • 初始化CallbacksQueues,内里存放5种范例的callback
  • 初始化FrameHandler,实现了handleMessage 方法
APP哀求Vsync

随着代码流程走到requestLayout(addView->setView->requestLayout->schduleTraversals)表现app要哀求vsync刷帧,具体看下哀求颠末
文件:frameworks/base/core/java/android/view/ViewRootImpl.java void scheduleTraversals() {        if (!mTraversalScheduled) {            mTraversalScheduled = true;            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();            // 添加CALLBACK_TRAVERSAL 范例的回调            mChoreographer.postCallback(                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);            notifyRendererOfFramePending();            pokeDrawLockIfNeeded();        }    }文件: frameworks/base/core/java/android/view/Choreographer.java private void postCallbackDelayedInternal(int callbackType,            Object action, Object token, long delayMillis) {        if (DEBUG_FRAMES) {            Log.d(TAG, "ostCallback: type=" + callbackType                    + ", action=" + action + ", token=" + token                    + ", delayMillis=" + delayMillis);        }        synchronized (mLock) {            final long now = SystemClock.uptimeMillis();            final long dueTime = now + delayMillis;            // mCallbackQueues[CALLBACK_TRAVERSAL] 队列添加一个回调            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);            if (dueTime <= now) {                // dueTime == now ,从这里进来                scheduleFrameLocked(now);            } else {                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);                msg.arg1 = callbackType;                msg.setAsynchronous(true);                mHandler.sendMessageAtTime(msg, dueTime);            }        }    }// CallbackRecord 是个单链表,有3个成员,dueTime,action,token和1个next指针// 将回调参加到当前的链表中public void addCallbackLocked(long dueTime, Object action, Object token) {            CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);            CallbackRecord entry = mHead;            if (entry == null) {                mHead = callback;                return;            }            if (dueTime < entry.dueTime) {                callback.next = entry;                mHead = callback;                return;            }            while (entry.next != null) {                if (dueTime < entry.next.dueTime) {                    callback.next = entry.next;                    break;                }                entry = entry.next;            }            entry.next = callback;        }// obtainCallbackLocked 的作用是假如当前pool内里没有回调,则新创建一个,假如有,则返回当前的回调并将mCallbackPool 指向下一个回调private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {        CallbackRecord callback = mCallbackPool;        if (callback == null) {            callback = new CallbackRecord();        } else {            mCallbackPool = callback.next;            callback.next = null;        }        callback.dueTime = dueTime;        callback.action = action;        callback.token = token;        return callback;    } private void scheduleFrameLocked(long now) {        if (!mFrameScheduled) {            mFrameScheduled = true;            if (USE_VSYNC) {                if (DEBUG_FRAMES) {                    Log.d(TAG, "Scheduling next frame on vsync.");                }               // 判断looper是不是在主线程,这两个方法殊途同归,都会实行scheduleVsyncLocked                if (isRunningOnLooperThreadLocked()) {                    scheduleVsyncLocked();                } else {                    Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);                    msg.setAsynchronous(true);                    mHandler.sendMessageAtFrontOfQueue(msg);                }          ...        }    }private void scheduleVsyncLocked() {        mDisplayEventReceiver.scheduleVsync();    }文件:frameworks/native/libs/gui/DisplayEventDispatcher.cppstatus_t DisplayEventDispatcher::scheduleVsync() {    if (!mWaitingForVsync) {        ...        status_t status = mReceiver.requestNextVsync();        if (status) {            ALOGW("Failed to request next vsync, status=%d", status);            return status;        }        mWaitingForVsync = true;    }    return OK;}文件:frameworks/native/libs/gui/DisplayEventReceiver.cpp status_t DisplayEventReceiver::requestNextVsync() {    if (mEventConnection != nullptr) {        mEventConnection->requestNextVsync();        return NO_ERROR;    }    return NO_INIT;}文件:frameworks/native/services/surfaceflinger/Scheduler/EventThread.cpp void EventThreadConnection::requestNextVsync() {    ATRACE_NAME("requestNextVsync");    mEventThread->requestNextVsync(this);}void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {    if (connection->resyncCallback) {        connection->resyncCallback();    }    std::lock_guard<std::mutex> lock(mMutex);    if (connection->vsyncRequest == VSyncRequest::None) {        connection->vsyncRequest = VSyncRequest::Single;        mCondition.notify_all();    }}跟着代码流程可以看到,终极调到app EventThread的requestNextVsync,将connection->vsyncRequest更新为Single,并唤醒mCondition的wait,用一副图表现。

1.png APP接收Vsync

sw-vsync分发必要具备两个条件:1. 有哀求vsync的动作 2. TimerDispatch线程定时时间到,会make一个vsync event。在当前帧哀求vsync,在下一帧创造vsync event后就会回调给app。
文件:frameworks/native/services/surfaceflinger/Scheduler/EventThread.cppvoid EventThread::threadMain(std::unique_lock<std::mutex>& lock) {DisplayEventConsumers consumers;    while (mState != State:uit) {        std:ptional<DisplayEventReceiver::Event> event;        // Determine next event to dispatch.        if (!mPendingEvents.empty()) {            event = mPendingEvents.front();            mPendingEvents.pop_front();      ...       if (!consumers.empty()) {             // 开始分发vsync event,假如是app eventthread就分发给app            dispatchEvent(*event, consumers);            consumers.clear();        }...}tatus_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {    ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);    return size < 0 ? status_t(size) : status_t(NO_ERROR);}文件:frameworks/native/libs/gui/DisplayEventReceiver.cppssize_t DisplayEventReceiver::sendEvents(gui::BitTube* dataChannel,        Event const* events, size_t count){    return gui::BitTube::sendObjects(dataChannel, events, count);}文件:frameworks/native/libs/gui/BitTube.cppssize_t BitTube::sendObjects(BitTube* tube, void const* events, size_t count, size_t objSize) {    const char* vaddr = reinterpret_cast<const char*>(events);    ssize_t size = tube->write(vaddr, count * objSize);    // should never happen because of SOCK_SEQPACKET    LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast<ssize_t>(objSize)),                        "BitTube::sendObjects(count=%zu, size=%zu), res=%zd (partial events were "                        "sent!)",                        count, objSize, size);    // ALOGE_IF(size<0, "error %d sending %d events", size, count);    return size < 0 ? size : size / static_cast<ssize_t>(objSize);}ssize_t BitTube::write(void const* vaddr, size_t size) {    ssize_t err, len;    do {        // 对端mReceiveFd,会唤醒epoll_wait        len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);        // cannot return less than size, since we're using SOCK_SEQPACKET        err = len < 0 ? errno : 0;    } while (err == EINTR);    return err == 0 ? len : -err;}对端mReceiveFd 被添加到epllo fd进行监听,当变瞎搅暂时就会实行回调函数handleEvent
文件:frameworks/native/libs/gui/DisplayEventDispatcher.cppint DisplayEventDispatcher::handleEvent(int, int events, void*) {    ...    nsecs_t vsyncTimestamp;    PhysicalDisplayId vsyncDisplayId;    uint32_t vsyncCount;    // 得到发送过来的vsync event    if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {        ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64              ", displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%d",              this, ns2ms(vsyncTimestamp), vsyncDisplayId, vsyncCount);        mWaitingForVsync = false;        // 处置处罚vsync event        dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);    }    return 1; // keep the callback}bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp,                                                  PhysicalDisplayId* outDisplayId,                                                  uint32_t* outCount) {    bool gotVsync = false;    DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];    ssize_t n;    // 获取发送过来的vsync event    while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {        ALOGV("dispatcher %p ~ Read %d events.", this, int(n));        for (ssize_t i = 0; i < n; i++) {            const DisplayEventReceiver::Event& ev = buf;            switch (ev.header.type) {                case DisplayEventReceiver:ISPLAY_EVENT_VSYNC:                    // Later vsync events will just overwrite the info from earlier                    // ones. That's fine, we only care about the most recent.                    gotVsync = true;                    *outTimestamp = ev.header.timestamp;                    *outDisplayId = ev.header.displayId;                    *outCount = ev.vsync.count;                    break;               ...    return gotVsync;}文件:frameworks/base/core/jni/android_view_DisplayEventReceiver.cppvoid NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,                                               uint32_t count) {    JNIEnv* env = AndroidRuntime::getJNIEnv();    ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));    if (receiverObj.get()) {        ALOGV("receiver %p ~ Invoking vsync handler.", this);        // 从jni调到java方法        env->CallVoidMethod(receiverObj.get(),                gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, displayId, count);        ALOGV("receiver %p ~ Returned from vsync handler.", this);    }    mMessageQueue->raiseAndClearException(env, "dispatchVsync");}文件:frameworks/base/core/java/android/view/DisplayEventReceiver.java private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) {        onVsync(timestampNanos, physicalDisplayId, frame);    }文件:frameworks/base/core/java/android/view/Choreographer.javapublic void onVsync(long timestampNanos, long physicalDisplayId, int frame) {            ...            mTimestampNanos = timestampNanos;            mFrame = frame;            // obtain 会new message,callback为FrameDisplayEventReceiver对象,实现了Runnable的方法            Message msg = Message.obtain(mHandler, this);            msg.setAsynchronous(true);            // 发送message,唤醒loop wait            mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);        }文件:frameworks/base/core/java/android/os/Message.java public static Message obtain(Handler h, Runnable callback) {        Message m = obtain();        m.target = h;        m.callback = callback;        return m;    }文件:frameworks/base/core/java/android/os/Handler.java  public void dispatchMessage(@NonNull Message msg) {        if (msg.callback != null) {            // callback 不为空,走handleCallback            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    } private static void handleCallback(Message message) {        // 实行FrameDisplayEventReceiver的run方法        message.callback.run();    }文件:frameworks/base/core/java/android/view/Choreographer.java  public void run() {            mHavePendingVsync = false;             // 处置处罚 App 的各种更新消息和回调            doFrame(mTimestampNanos, mFrame);        }    }从链路来看,末了会调到doFrame来处置处罚 App 的各种更新消息和回调,用个图总结下。

APP处置处罚Vsync

app接收到vsync信号后,就开始实行各种更新消息和回调,重要的处置处罚逻辑在doFrame函数。
文件:frameworks/base/core/java/android/view/Choreographer.javavoid doFrame(long frameTimeNanos, int frame) {        // 处置处罚掉帧逻辑,临时不看        ...        try {            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");            AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);            // 纪录input开始时间            mFrameInfo.markInputHandlingStart();            // 回调input方法            doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);            //纪录动画开始时间            mFrameInfo.markAnimationsStart();             //回变动画方法               doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);            doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);             // 纪录Traversal开始时间            mFrameInfo.markPerformTraversalsStart();              // 回调Traversal 方法,重点看下            doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);            doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);        } finally {            AnimationUtils.unlockAnimationClock();            Trace.traceEnd(Trace.TRACE_TAG_VIEW);        }        if (DEBUG_FRAMES) {            final long endNanos = System.nanoTime();            Log.d(TAG, "Frame " + frame + ": Finished, took "                    + (endNanos - startNanos) * 0.000001f + " ms, latency "                    + (startNanos - frameTimeNanos) * 0.000001f + " ms.");        }    } void doCallbacks(int callbackType, long frameTimeNanos) {            ...            //取出对应的callback,还记得前面是通过addCallbackLocked将callback参加到链表内里,现将对应的callback取出            callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(                    now / TimeUtils.NANOS_PER_MS);            if (callbacks == null) {                return;            }            mCallbacksRunning = true;            ...        try {            Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);            for (CallbackRecord c = callbacks; c != null; c = c.next) {                if (DEBUG_FRAMES) {                    Log.d(TAG, "RunCallback: type=" + callbackType                            + ", action=" + c.action + ", token=" + c.token                            + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));                }                // 实行CallbackRecord的run方法                c.run(frameTimeNanos);            }        ...            Trace.traceEnd(Trace.TRACE_TAG_VIEW);        }    } private static final class CallbackRecord {        public CallbackRecord next;        public long dueTime;        public Object action; // Runnable or FrameCallback        public Object token;        @UnsupportedAppUsage        public void run(long frameTimeNanos) {            if (token == FRAME_CALLBACK_TOKEN) {                ((FrameCallback)action).doFrame(frameTimeNanos);            } else {                // 实行mTraversalRunnable的run方法,在scheduleTraversals内里通过postCallback参加callback链表                ((Runnable)action).run();            }        }    }文件:frameworks/base/core/java/android/view/ViewRootImpl.java final class TraversalRunnable implements Runnable {        @Override        public void run() {            //末了回调到这个方法,处置处罚measure、layout、draw             doTraversal();        }    } private void performTraversals() {... performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);... performLayout(lp, mWidth, mHeight);... performDraw();...}可以看到当app接收到vsync信号后就开始处置处罚各种回调的方法,由于有些内容并不是很熟悉,也就没能继承分析下去,文章只是分析了大致的流程,具体的细节碰到题目再分析。
文章从app哀求vsync,eventThread分发vsync,再到app处置处罚vsync,分析了大致的流程,也印证了文章开始说的Choreographer作用: 1. 负责哀求和接收 Vsync 信号 2. 负责接收和处置处罚 App 的各种更新消息和回调,比及 Vsync 到来的时间同一处置处罚。
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-11-22 01:43, Processed in 0.214683 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表