Android系统_Choreographer工作流程分析

基于API 23w

图文概述

Choreographer 编舞者。统一动画、输入和绘制时机
Choreographer 的作用,主要是配合 Vsync ,给上层 App 的渲染提供一个稳定的 Message 处理的时机,即 Vsync 到来的时候 ,系统通过对 Vsync 信号周期的调整,来控制每一帧绘制操作的时机

Choreographer启动流程

Window添加流程中,当Activity启动执行onResume后,会执行到创建ViewRootImpt Android系统_Window的创建和添加流程分析

public ViewRootImpl(Context context, Display display) {
   ...
   // VoewRootImpl 构造方法 会获取Choreographer实例
   mChoreographer = Choreographer.getInstance();
   ...
}

Choreographer构造

通过单例模式构建,这里是每一个线程有一个Choreographer对象,而这里的线程为应用进程的主线程

public static Choreographer getInstance() {
   return sThreadInstance.get(); //单例模式
}

private static final ThreadLocal<Choreographer> sThreadInstance =
   new ThreadLocal<Choreographer>() {

   protected Choreographer initialValue() {
       Looper looper = Looper.myLooper(); //获取当前线程的Looper
       if (looper == null) {
           throw new IllegalStateException("The current thread must have a looper!");
       }
       return new Choreographer(looper); 创建
   }
};

Choreographer构造方法

初始化一个Looper和一个FrameHandler变量用来处理消息,另外创建了一个 FrameDisplayEventReceiver用来请求和接受Vysnc事件

private Choreographer(Looper looper) {
   mLooper = looper;
   //创建Handler对象
   mHandler = new FrameHandler(looper);
   //创建用于接收VSync信号的对象 (使用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

Choreographer 处理绘制的逻辑核心在 Choreographer.doFrame 函数中,doFrame 函数主要做三件事情,计算掉帧逻辑、记录帧绘制信息、
执行 CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_INSETS_ANIMATION、CALLBACK_TRAVERSAL、CALLBACK_COMMIT

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

它继承DisPlayEvetReceiver,调用父类构造方法
另外FrameDisplayEventReceiver中三个比较重要的方法

  • onVsync – Vsync 信号回调
  • run – 执行 doFrame
  • scheduleVsync – 请求 Vsync 信号
private final class FrameDisplayEventReceiver extends DisplayEventReceiver implements Runnable {
           
       public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
        super(looper, vsyncSource);
       }
           
       @Override
       public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
          ......
          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);
       }
           
       public void scheduleVsync() {
          ......  
          nativeScheduleVsync(mReceiverPtr);
          
       }
}

DisplayEventReceiver构造

public DisplayEventReceiver(Looper looper) {
   mMessageQueue = looper.getQueue(); //获取主线程的消息队列
   // 通过JNI执行native层初始化
   mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue);
}

android_view_DisplayEventReceiver.cpp 初始化

创建NativeDisplayEventReceiver, 监听mReceiver的所获取的文件句柄,一旦有数据到来,则回调this(此处NativeDisplayEventReceiver)中所复写LooperCallback对象的 handleEvent

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject messageQueueObj) {
   sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
   ...
   //创建NativeDisplayEventReceiver
   sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
           receiverWeak, messageQueue);
   //初始化
   status_t status = receiver->initialize();
   ...

   //获取DisplayEventReceiver对象的引用
   receiver->incStrong(gDisplayEventReceiverClassInfo.clazz);
   return reinterpret_cast<jlong>(receiver.get());
}

// NativeDisplayEventReceiver继承于LooperCallback对象,此处mReceiverWeakGlobal记录的是Java层 DisplayEventReceiver对象的全局引用
NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
       jobject receiverWeak, const sp<MessageQueue>& messageQueue) :
       mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
       mMessageQueue(messageQueue), mWaitingForVsync(false) {
   ALOGV("receiver %p ~ Initializing display event receiver.", this);
}

status_t NativeDisplayEventReceiver::initialize() {
   //mReceiver为DisplayEventReceiver类型
   status_t result = mReceiver.initCheck();
   ...
   //监听mReceiver的所获取的文件句柄。
   int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
           this, NULL);
   ...

   return OK;
}

Callback添加流程

Choreographer提供postCallback和postFrameCallback两种回调方式及对应的delay两种,其最终执行的内部postCallbackDelayedInternal方法

Choreographer.postCallbackDelayedInternal

创建Callback,然后添加到mCallbackQueues队列上,
然后根据是否立即执行,决定是发消息还是直接调用
最终执行scheduleFrameLocked方法

private void postCallbackDelayedInternal(int callbackType,
       Object action, Object token, long delayMillis) {
   synchronized (mLock) {
       //当前时间
       final long now = SystemClock.uptimeMillis();
       //回调执行时间,=当前时间+delay时间
       final long dueTime = now + delayMillis;
       //添加到callback队列
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.scheduleFrameLocked

使用Vsync,按时间执行到scheduleVsyncLocked方法

private void scheduleFrameLocked(long now) {
   if (!mFrameScheduled) {
       mFrameScheduled = true;
       if (USE_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()) {
               // 请求Vsync信号,最终会调用到native层,natie层处理完成后出发onVsync信号接收回调流程
               scheduleVsyncLocked();
           } else {
               // 发送消息,delay后执行此方法
               Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
               msg.setAsynchronous(true);
               mHandler.sendMessageAtFrontOfQueue(msg);
           }
       } else {
            // 没有使用Vsync 则直接发送msg,然后调用doFrame
           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);
       }
   }
}

Choreographer.scheduleVsyncLocked

执行FrameDisplayEventReceiver.scheduleVsync
di层向SurfaceFlinger服务注册,即下一次Vsync事件会调用DisplayEventReceiver的disptachVsync方法


private void scheduleVsyncLocked() {
   mDisplayEventReceiver.scheduleVsync();
}
    
public void scheduleVsync() {
    nativeScheduleVsync(mReceiverPtr);
}

Vsync回调流程

当vysnc信号由底层HWC触发后会执行android_view_DisplayEventReceiver的handleEvent方法。
JNI层接受HWC的Vysnc信号,过滤处理,分发到Java层DisplayEventReceiver

android_view_DisplayEventReceiver.handleEvent

int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* data) {
   ...
   nsecs_t vsyncTimestamp;
   int32_t vsyncDisplayId;
   uint32_t vsyncCount;
   //清除所有的pending事件,只保留最后一次vsync
   if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
       mWaitingForVsync = false;
       //分发Vsync
       dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
   }
   return 1;
}

// 遍历所有的事件,当有多个VSync事件到来,则只关注最近一次的事件
bool NativeDisplayEventReceiver::processPendingEvents(
       nsecs_t* outTimestamp, int32_t* outId, uint32_t* outCount) {
   bool gotVsync = false;
   DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
   ssize_t n;
   while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
       for (ssize_t i = 0; i < n; i++) {
           const DisplayEventReceiver::Event& ev = buf[i];
           switch (ev.header.type) {
           case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
               gotVsync = true; //获取VSync信号
               *outTimestamp = ev.header.timestamp;
               *outId = ev.header.id;
               *outCount = ev.vsync.count;
               break;
           case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
               dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected);
               break;
           default:
               break;
           }
       }
   }
   return gotVsync;
}

// 分发Vsync ,DisplayEventReceiver进行接受
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()) {
       // 此处调用到Java层的DisplayEventReceiver对象的dispatchVsync()方法,执行进入Java层
       env->CallVoidMethod(receiverObj.get(),
               gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);
   }

   mMessageQueue->raiseAndClearException(env, "dispatchVsync");
}

FrameDisplayEventReceiver.onVsync

Java层接受Vsync事件,通过Handler通信机制发送消息,后续执行到它自身的run方法,然后执行doFrame操作

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

    @Override
    public void run() {
        mHavePendingVsync = false;
        doFrame(mTimestampNanos, mFrame);
    }
    
    @Override
    public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
        ...
        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);
    }
    ...
}


Choreographer.doFrame

  • 先判断Vsync信号间隔时间和刷新时间是否符合
  • 顺序执行4种时间对应的CallbackQueue队列中注册的回调函数
    1. CALLBACK_INPUT : 处理输入事件处理有关
    2. CALLBACK_ANIMATION : 处理 Animation 的处理有关
    3. CALLBACK_INSETS_ANIMATION : 处理 Insets Animation 的相关回调
    4. CALLBACK_TRAVERSAL : 处理和 UI 等控件绘制有关
    5. CALLBACK_COMMIT : 处理 Commit 相关回调
void doFrame(long frameTimeNanos, int frame) {
    final long startNanos;
    synchronized (mLock) {
        // 每调用一次scheduleFrameLocked(),则mFrameScheduled=true,能执行一次doFrame()操作,执行完doFrame()并设置mFrameScheduled=false;
        if (!mFrameScheduled) {
            return; // mFrameScheduled=false,则直接返回。
        }
        //原本计划的绘帧时间点
        long intendedFrameTimeNanos = frameTimeNanos;        
        //起始时间
        startNanos = System.nanoTime();
        //计算消息发送与函数调用开始之间所花费的时间
        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信号到达的时间戳,如果frameTimeNanos小于一个屏幕刷新周期,则重新请求VSync信号
        if (frameTimeNanos < mLastFrameTimeNanos) {
            scheduleVsyncLocked();
            return;
        }

        mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
        mFrameScheduled = false;
        mLastFrameTimeNanos = frameTimeNanos;
    }

    try {
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");

        mFrameInfo.markInputHandlingStart();
        //执行4种事件对应的回调方法
        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.doCallbacks

  • 从队列头mHead查找CallbackRecord对象,当队列头部的callbacks对象为空或者执行时间还没到达,则直接返回;
  • 开始执行相应回调的run()方法;
  • 回收callbacks,加入对象池mCallbackPool,就是说callback一旦执行完成,则会被回收。
void doCallbacks(int callbackType, long frameTimeNanos) {
    CallbackRecord callbacks;
    synchronized (mLock) {
        final long now = System.nanoTime();
        // 从队列查找相应类型的CallbackRecord对象
        callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
                now / TimeUtils.NANOS_PER_MS);
        if (callbacks == null) {
            return;  //当队列为空,则直接返回
        }
        mCallbacksRunning = true;

        if (callbackType == Choreographer.CALLBACK_COMMIT) {
            final long jitterNanos = now - frameTimeNanos;
            //当commit类型回调执行的时间点超过2帧,则更新mLastFrameTimeNanos。
            if (jitterNanos >= 2 * mFrameIntervalNanos) {
                final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
                        + mFrameIntervalNanos;
                frameTimeNanos = now - lastFrameOffset;
                mLastFrameTimeNanos = frameTimeNanos;
            }
        }
    }
    try {
        for (CallbackRecord c = callbacks; c != null; c = c.next) {
            c.run(frameTimeNanos); 
        }
    } finally {
      synchronized (mLock) {
          mCallbacksRunning = false;
          //回收callbacks,加入对象池mCallbackPool
          do {
              final CallbackRecord next = callbacks.next;
              recycleCallbackLocked(callbacks);
              callbacks = next;
          } while (callbacks != null);
      }
      Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}

CallbackRecord.run

  • 当token的数据类型为FRAME_CALLBACK_TOKEN,则执行该对象的doFrame()方法;
  • 当token为其他类型,则执行该对象的run()方法。
private static final class CallbackRecord {
    public CallbackRecord next;
    public long dueTime;
    public Object action; // Runnable或者 FrameCallback
    public Object token;

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

Choreographer.CALLBACK_TRAVERSAL

这里主要分析Traversal类型,即View的绘制流程

  • ViewRootImpl.scheduleTraversals , 添加callback
  • 回调 TraversalRunnable.run 方法
  • 开始View的绘制流程
void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        //为了提高优先级,先 postSyncBarrier
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    }
}

final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        // 真正开始执行 measure、layout、draw
        doTraversal();
    }
}
void doTraversal() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        // 这里把 SyncBarrier remove
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
        // 真正开始
        performTraversals();
    }
}
private void performTraversals() {
      // measure 操作
      if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight() || contentInsetsChanged || updatedConfiguration) {
            performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
      }
      // layout 操作
      if (didLayout) {
          performLayout(lp, mWidth, mHeight);
      }
      // draw 操作
      if (!cancelDraw && !newSurface) {
          performDraw();
      }
}

推荐阅读:图形系统总结
参考
Android 基于 Choreographer 的渲染机制详解
Choreographer原理
源码分析

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266