Android Framework 窗口子系统(06)Choreographer机制

系列文章解读&说明:

Android Framework 窗口子系统 的 分析主要分为以下部分:

(01)WindowMangerService基础知识

(02)应用进程和WindowManagerService之间的关系

(03)窗口显示次序

(04)确定窗口尺寸

(05)窗口布局说明

(06)Choreographer机制

(07)窗口动画系统

本模块分享的内容:Choreographer机制

本章关键点总结 & 说明:

该图关注➕思维导图中左上:Choreographer机制 部分即可,主要说明Choreographer机制的对外接口,这里做了简单的源码分析,对其原理有一定的了解。放大 Choreographer机制 的局部图,效果如下:

Choreographer机制说明:该机制是android 4.2之后 推出的API,和handler的post机制类似,区别在于Choreographer的处理时机是 屏幕的垂直同步Vsync事件到来之时,其处理回调的过程被当作渲染下一帧工作的一部分。

对于动画而言,Choreographer对外接口说明如下:

  1. postCallback(int callbackType, Runnable action, Object token):下一次Vsync时执行action参数指定的操作。callbackType的参数可以是CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL
  2. postCallbackDelayed(...):同上,只是加了延迟时间而已。
  3. postFrameCallback(int callbackType, Runnable action, Object token):分析源码可知,就是封装了postCallback,callbackType参数为CALLBACK_ANIMATION而已。
  4. postFrameCallbackDelayed(...):同上,只是加了延迟时间而已。

后面会通过源码进行深入的说明。接下来开始进入Choreographer源码解读

1 Choreographer分析

在Activity启动过程,执行完onResume后,层层调用后会到addView(),再到ViewRootImpl构造器,代码如下:

public ViewRootImpl(Context context, Display display) {
    //...
    mChoreographer = Choreographer.getInstance();
    //...
}

继续分析getInstance,代码如下:

    public static Choreographer getInstance() {
        return sThreadInstance.get();
    }

继续分析sThreadInstance.get,代码如下:

private static final ThreadLocal<Choreographer> sThreadInstance =
            new ThreadLocal<Choreographer>() {
        @Override
        protected Choreographer initialValue() {
            Looper looper = Looper.myLooper();//获取当前线程looper
            //...
            return new Choreographer(looper);
        }
    };

当前线程为UI线程,因此get获得的就是Choreographer(looper);继续分析Choreographer构造器,代码如下:

private Choreographer(Looper looper) {
    mLooper = looper;
    mHandler = new FrameHandler(looper);//handler对象
    //用于接收VSync信号
    mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;

    //是指上一次帧绘制时间点;
    mLastFrameTimeNanos = Long.MIN_VALUE;

    //帧间时长,一般等于16.7ms
    mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());

    //创建回调对象
    mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];

    for (int i = 0; i <= CALLBACK_LAST; i++) {
        mCallbackQueues[i] = new CallbackQueue();
    }
}

接下来我们关注两个变量:FrameHandler和FrameDisplayEventReceiver。

1.1 FrameHandler分析

代码如下:

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

这里可知:handler可以处理三种消息,帧消息,VSYNC,CALLBACK。

1.2 FrameDisplayEventReceiver创建

代码如下:

private final class FrameDisplayEventReceiver extends DisplayEventReceiver
        implements Runnable {
    private boolean mHavePendingVsync;
    private long mTimestampNanos;
    private int mFrame;

    public FrameDisplayEventReceiver(Looper looper) {
        super(looper);
    }

    @Override
    public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
        if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
            scheduleVsync();
            return;
        }

        long now = System.nanoTime();
        if (timestampNanos > now) {
            timestampNanos = now;
        }

        if (mHavePendingVsync) {
			
        } else {
            mHavePendingVsync = true;
        }

        mTimestampNanos = timestampNanos;
        mFrame = frame;
        Message msg = Message.obtain(mHandler, this);
        msg.setAsynchronous(true);
        mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
    }

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

这里当有Vsync信号上报时会回调onVSync方法,它使用handler发送消息给主线程Looper,消息自带callback,内容为FrameDisplayEventReceiver。 当主线程Looper执行到该消息时调用FrameDisplayEventReceiver.run()方法。这里沿着run方法,继续分析doFrame,代码如下:

void doFrame(long frameTimeNanos, int frame) {
    final long startNanos;
    synchronized (mLock) {
        if (!mFrameScheduled) {
            return; // no work to do
        }
        startNanos = System.nanoTime();
        final long jitterNanos = startNanos - frameTimeNanos;
        if (jitterNanos >= mFrameIntervalNanos) {
            final long skippedFrames = jitterNanos / mFrameIntervalNanos;
            final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
            frameTimeNanos = startNanos - lastFrameOffset;
        }
        if (frameTimeNanos < mLastFrameTimeNanos) {
            scheduleVsyncLocked();
            return;
        }
        mFrameScheduled = false;
        mLastFrameTimeNanos = frameTimeNanos;
    }

    doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
    doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
    doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
}
  1. 这里每调用一次scheduleFrameLocked(),则mFrameScheduled=true,能执行一次doFrame()操作,执行完doFrame()并设置mFrameScheduled=false;
  2. 最终有3个回调类别,如下所示:
    • INPUT:输入事件
    • ANIMATION:动画
    • TRAVERSAL:窗口刷新,执行measure/layout/draw操作

这里继续分析doCallbacks,代码如下:

void doCallbacks(int callbackType, long frameTimeNanos) {
    CallbackRecord callbacks;
    synchronized (mLock) {
        final long now = SystemClock.uptimeMillis();
        callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now);
        mCallbacksRunning = true;
    }
    try {
        for (CallbackRecord c = callbacks; c != null; c = c.next) {
            c.run(frameTimeNanos);
        }
    } finally {
        synchronized (mLock) {
            mCallbacksRunning = false;
            do {
                final CallbackRecord next = callbacks.next;
                recycleCallbackLocked(callbacks);
                callbacks = next;
            } while (callbacks != null);
        }
    }
}

这段代码总结如下:

  1. 只要callback不为null,则开始执行相应回调的run()方法;
  2. 回收callbacks,加入对象池mCallbackPool,就是说callback一旦执行完成,则会被回收。

接下来我们继续分析下CallbackRecord类,代码如下:

private static final class CallbackRecord {
        public CallbackRecord next;
        public long dueTime;
        public Object action; // Runnable or FrameCallback
        public Object token;

        public void run(long frameTimeNanos) {
            if (token == FRAME_CALLBACK_TOKEN) {
                ((FrameCallback)action).doFrame(frameTimeNanos);
            } else {
                ((Runnable)action).run();
            }
        }
    }

这里的回调run()有两种情况:

  1. 当token为FRAME_CALLBACK_TOKEN,则执行该对象的doFrame()方法。
  2. 当token为其他类型时,则执行该对象的run()方法。

2 动画显示过程

WMS是通过调用scheduleAnimationLocked()方法来设置mFrameScheduled=true来触发动画, 下面分析动画控制的过程。代码如下:

void scheduleAnimationLocked() {
    if (!mAnimationScheduled) {
        mAnimationScheduled = true;
        mChoreographer.postCallback(
                Choreographer.CALLBACK_ANIMATION, mAnimator.mAnimationRunnable, null);
    }
}

只有当mAnimationScheduled=false时,才会执行postCallback(),其中参数为mAnimator.mAnimationFrameCallback。

2.1 这里对参数mAnimator.mAnimationFrameCallback进行分析

mAnimator该对象类型为WindowAnimator,在WMS中定义:

private WindowManagerService( 
    //...
    mAnimator = new WindowAnimator(this); 
    //...
}

WindowAnimator的构造器如下:

WindowAnimator(final WindowManagerService service) {
    mService = service;
    mContext = service.mContext;
    mPolicy = service.mPolicy;

    mAnimationRunnable = new Runnable() {
        @Override
        public void run() {
            synchronized (mService.mWindowMap) {
                mService.mAnimationScheduled = false;
                animateLocked();
            }
        }
    };
}

分析到这里,如果下一个VSync到来,将会执行到animateLocked方法。

2.2 对mChoreographer.postCallback进行分析

postCallback代码实现如下:

public void postCallback(int callbackType, Runnable action, Object token) {
        postCallbackDelayed(callbackType, action, token, 0);
    }

继续分析postCallbackDelayed,代码如下:

public void postCallbackDelayed(int callbackType,
        Runnable action, Object token, long delayMillis) {
    //容错处理...
    postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}

继续分析postCallbackDelayedInternal,代码如下:

// 参数说明:
/*callbackType为动画
  action为mAnimationFrameCallback
  token为FRAME_CALLBACK_TOKEN
  delayMillis=0
*/
private void postCallbackDelayedInternal(int callbackType,
        Object action, Object token, long delayMillis) {
    synchronized (mLock) {
        final long now = SystemClock.uptimeMillis();
        final long dueTime = now + delayMillis;
        //添加到 mCallbackQueues队列
        mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

        if (dueTime <= now) {
            scheduleFrameLocked(now);
        } else {
            //发送消息MSG_DO_SCHEDULE_CALLBACK
            Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
            msg.arg1 = callbackType;
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, dueTime);
        }
    }
}

这里最后发送的消息类型是MSG_DO_SCHEDULE_CALLBACK,handler收到后处理如前面所示:

private final class FrameHandler extends Handler {

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

这里继续分析doScheduleCallback,代码如下所示:

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

继续分析scheduleFrameLocked,代码实现如下:

private void scheduleFrameLocked(long now) {
    if (!mFrameScheduled) {
        mFrameScheduled = true;
        if (USE_VSYNC) {
            if (isRunningOnLooperThreadLocked()) {
                scheduleVsyncLocked();//当运行在Looper线程,则立刻调度vsync
            } else {
                //发送给UI线程
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtFrontOfQueue(msg);
            }
        } else {
            //...
        }
    }
}

这里注意,当运行在其他线程时,通过发送一个消息到Looper线程,然后通过handler处理消息执行scheduleVsyncLocked();

接下来分析scheduleVsyncLocked的核心实现,代码如下:

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

继续分析mDisplayEventReceiver的scheduleVsync实现,代码如下:

public void scheduleVsync() {
        if (mReceiverPtr == 0) {
            Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
                    + "receiver has already been disposed.");
        } else {
            nativeScheduleVsync(mReceiverPtr);
        }
    }

这里nativeScheduleVsync函数的实现,代码如下:

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

这里继续分析receiver->scheduleVsync();,代码实现如下:

status_t NativeDisplayEventReceiver::scheduleVsync() {
    if (!mWaitingForVsync) {
        // Drain all pending events.
        nsecs_t vsyncTimestamp;
        int32_t vsyncDisplayId;
        uint32_t vsyncCount;
        //清除所有的pending事件,只保留最后一次vsync
        processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount);
        status_t status = mReceiver.requestNextVsync();
        mWaitingForVsync = true;
    }
    return OK;
}

这里关注mReceiver.requestNextVsync();代码实现如下:

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

该方法的作用请求下一次Vsync信息处理,当Vsync信号到来,由于mFrameScheduled = true,则继续执行第1部分中最后部分中的CallbackRecord.run()方法。

使用说明:避免在执行动画渲染的前后在主线程放入耗时操作,否则会造成卡顿感,影响用户体验。

猜你喜欢

转载自blog.csdn.net/vviccc/article/details/94616956
今日推荐