Android绘制机制流程分析

一、基本概念

        在一个典型的显示系统中,一般包括CPU、GPU、display三个部分, CPU负责计算数据,把计算好数据交给GPU,GPU会对图形数据进行渲染,渲染好后放到buffer里存起来,然后display 负责把buffer里的数据呈现到屏幕上。

        显示过程,简单的说就是CPU/GPU准备好数据,存入buffer,display每隔一段时间去buffer里取数据,然后显示出来。display读取的频率是固定的,比如每个16ms读一次,但是CPU/GPU写数据是完全无规律的。

  • 在GPU中有一块缓冲区叫做 Frame Buffer ,这个帧缓冲区可以认为是存储像素值的二位数组。
  • 数组中的每一个值就对应了手机屏幕的像素点需要显示的颜色。
  • 由于这个帧缓冲区的数值是在不断变化的,所以只要完成对屏幕的刷新就可以显示不同的图像了.
  • GPU 除了帧缓冲区用以交给手机屏幕进行绘制外. 还有一个缓冲区 Back Buffer 这个用以交给应用的,让CPU往里面填充数据。
    GPU会定期交换 Back Buffer 和 Frame Buffer ,也就是对Back Buffer中的数据进行栅格化后将其转到 Frame Buffer 然后交给屏幕进行显示绘制,同时让原先的Frame Buffer 变成 Back Buffer 让程序处理。

        上述内容概括一下:屏幕的刷新包括三个步骤:CPU 计算屏幕数据、GPU 进一步处理和缓存、最后 display 再将缓存中(buffer)的屏幕数据显示出来。

        对于 Android 而言:CPU 计算屏幕数据指的就是 View 树的绘制过程,也就是 Activity 对应的视图树从根布局 DecorView 开始层层遍历每个 View,分别执行测量、布局、绘制三个操作的过程。也就是说,我们常说的 Android 每隔 16.6ms 刷新一次屏幕其实是指:底层以固定的频率,比如每 16.6ms 将 buffer 里的屏幕数据显示出来。

二、基本名词

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

        SurfaceFlinger 接受来自多个源的数据缓冲区,然后将它们进行合成并发送到显示屏,Client测量和计算布局,SurfaceFlinger(server)用来渲染绘制界面,client和server的是通过匿名共享内存(SharedClient)通信。每个应用和SurfaceFlienger之间都会创建一个SharedClient,一个SharedClient最多可以创建31个SharedBufferStack,每个surface对应一个SharedBufferStack,也就是一个Window。也就意味着,每个应用最多可以创建31个窗口

        Hardware Composer HAL (HWC) 确定使用可用硬件合成缓冲区的最有效的方法,代表着硬件显示设备,注册了 VSYNC 信号的回调

        Vsync 垂直同步机制,当屏幕从缓冲区扫描完一帧到屏幕上之后,开始扫描下一帧之前,发出的一个同步信号,该信号用来切换前缓冲区和后缓冲区,扫描一帧的同步时间,Android手机一般为60HZ(也就是1秒刷新60帧,大约16.67毫秒刷新1帧);

三、Android View绘制流程

        Android应用程序请求SurfaceFlinger服务创建Surface的过程。有了Surface之后,Android应用程序就可以在上面绘制自己的UI了,接着再请求SurfaceFlinger服务将这个已经绘制好了UI的Surface渲染到设备显示屏上去

        应用层的一个Activity对应一个根View(也就是一个DecorView)、一个WindowState、一个ViewRootImpl,每个对象都非常重要,都是在Activity添加过程中重量级的对象,DecorView是当前Activity的根View,它里面管理着当前界面的View树;WindowState对象是当前Activity窗口在WindowManagerService中代理对象;ViewRootImpl则肩负着View的标准三步曲的处理和事件分发,而View绘制也是由Choreographer指导的。

        看下Choreographer方法

private Choreographer(Looper looper) {
    mLooper = looper;
    mHandler = new FrameHandler(looper); // 根据是否使用了VSYNC来创建一个FrameDisplayEventReceiver对象
    mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
    mLastFrameTimeNanos = Long.MIN_VALUE;//是指上一次帧绘制时间点
    mFrameIntervalNanos = (long) (1000000000 / getRefreshRate());//帧间时长,一般等于16.7ms
    Callback mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];// CALLBACK_LAST + 1 = 4,创建一个容量为4的CallbackQueue数组,用来存放4种不同的
    for (int i = 0; i <= CALLBACK_LAST; i++) {
        mCallbackQueues[i] = new CallbackQueue();
    }
}

        Choreographer类中有一个Looper和一个FrameHandler变量。变量USE_VSYNC用于表示系统是否是用了Vsync同步机制,该值是通过读取系统属性debug.choreographer.vsync来获取的。如果系统使用了Vsync同步机制,则创建一个FrameDisplayEventReceiver对象用于请求并接收Vsync事件,最后Choreographer创建了一个大小为3的CallbackQueue队列数组,用于保存不同类型的Callback。

这里,不同类型的Callback包括如下4种

public static final int CALLBACK_INPUT = 0//输入

public static final int CALLBACK_ANIMATION = 1//动画

public static final int CALLBACK_TRAVERSAL = 2//视图绘制

public static final int CALLBACK_COMMIT = 3//提交

 Choreographer postCallback()->postCallbackDelayed()->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);
        }
    }
}

        该postCallback方法向回调请求数组CallbackQueues中存入一个对应类型的记录CallbackRecord,该纪录封装回调任务、当前时间,等待信号安排一帧绘制。数组元素是CallbackQueue,内部包含指向CallbackRecord链表的头指针

private void scheduleFrameLocked(long now) {
    if (!mFrameScheduled) {
        mFrameScheduled = true;
        if (USE_VSYNC) {
            if (DEBUG_FRAMES) {
                Log.d(TAG, "Scheduling next frame on vsync.");
            }
 
            // If running on the Looper thread, then schedule the vsync immediately,
            // otherwise post a message to schedule the vsync from the UI thread
            // as soon as possible.
            if (isRunningOnLooperThreadLocked()) {
                scheduleVsyncLocked(); // 请求VSYNC信号,最终会调到Native层,Native处理完成后触发FrameDisplayEventReceiver的onVsync回调,
                //回调中最后也会调用doFrame(long frameTimeNanos, int frame)方法
            } else {
                // 在UI线程上直接发送一个what=MSG_DO_SCHEDULE_VSYNC的消息,最终也会调到scheduleVsyncLocked()去请求VSYNC信号
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtFrontOfQueue(msg);
            }
        } else {
            //如果没有VSYNC的同步,则发送消息刷新画面
            final long nextFrameTime = Math.max(
                    mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
            if (DEBUG_FRAMES) {
                Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
            }
            Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, nextFrameTime);
        }
    }
}
 
private void scheduleVsyncLocked() {
    mDisplayEventReceiver.scheduleVsync();
}

        mDisplayEventReceiver 对应的是FrameDisplayEventReceiver,它继承自 DisplayEventReceiver , 主要是用来接收同步脉冲信号 VSYNC。scheduleVsync()方法通过底层nativeScheduleVsync()向SurfaceFlinger 服务注册,即在下一次脉冲接收后会调用 jni端会通过CallVoidMethod方法调用到java端的DisplayEventReceiver的dispatchVsync方法,继而调用到FrameDisplayEventReceiver的onVsync方法

private final class FrameDisplayEventReceiver extends DisplayEventReceiver implements Runnable {
    private boolean mHavePendingVsync;
    private long mTimestampNanos;
    private int mFrame;
 
    @Override
    public void onVsync(long timestampNanos, int builtInDisplayId, int frame) { //忽略来自第二显示屏的Vsync
        if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
            scheduleVsync();
            return;
        } ...mTimestampNanos = timestampNanos;
        mFrame = frame; //该消息的callback为当前对象FrameDisplayEventReceiver
        Message msg = Message.obtain(mHandler, this);
        msg.setAsynchronous(true); //此处mHandler为FrameHandler
        mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
    }
 
    @Override
    public void run() {
        mHavePendingVsync = false;
        doFrame(mTimestampNanos, mFrame);
    }
}

        onVsync()过程是通过FrameHandler向主线程Looper发送了一个自带callback的消息 callback为FrameDisplayEventReceiver。 当主线程Looper执行到该消息时,则调用FrameDisplayEventReceiver.run()方法,紧接着便是调用doFrame

void doFrame(long frameTimeNanos, int frame) {
    final long startNanos;
    synchronized (mLock) {
        if (!mFrameScheduled) {
            return; // mFrameScheduled=false,则直接返回。
        }
        long intendedFrameTimeNanos = frameTimeNanos; //原本计划的绘帧时间点
        startNanos = System.nanoTime();//保存起始时间 //由于Vsync事件处理采用的是异步方式,因此这里计算消息发送与函数调用开始之间所花费的时间
        final long jitterNanos = startNanos - frameTimeNanos; //如果线程处理该消息的时间超过了屏幕刷新周期
        if (jitterNanos >= mFrameIntervalNanos) { //计算函数调用期间所错过的帧数
            final long skippedFrames = jitterNanos / mFrameIntervalNanos; //当掉帧个数超过30,则输出相应log
            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;
            frameTimeNanos = startNanos - lastFrameOffset; //对齐帧的时间间隔 }
            //如果frameTimeNanos小于一个屏幕刷新周期,则重新请求VSync信号
            if (frameTimeNanos < mLastFrameTimeNanos) {
                scheduleVsyncLocked();
                return;
            }
            mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
            mFrameScheduled = false;
            mLastFrameTimeNanos = frameTimeNanos;
        }
        try {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame"); //分别回调CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL事件
            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 {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }
}

        Choreographer内部维护了这四种链表,渲染每一帧的时候都会从上往下的去执行相应的渲染操作,有输入那么就先渲染输入队列,有动画就渲染动画,然后遍历,然后提交

void doCallbacks(int callbackType, long frameTimeNanos) {
    CallbackRecord callbacks;
    synchronized (mLock) { ...final long now = System.nanoTime();
        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));
            }
            c.run(frameTimeNanos);
        }
    } finally {
        synchronized (mLock) {
            mCallbacksRunning = false;
            do {
                final CallbackRecord next = callbacks.next;
                recycleCallbackLocked(callbacks);
                callbacks = next;
            } while (callbacks != null);
        }
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值