注册
  • 凯时最新首页登录时尚网欢迎您!

高性价比:Systrace 之Chore奔驰GLC 300e首发,豪华这就是微信的狭隘,马化腾的狭隘

主页 > 凯时最新首页登录时尚网 > 服饰 > 正文
>

Systrace 之Choreographer 机制

[提要]和你一起终身学习,这里是程序员 Android本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容:一、主线程运行机制的本质二、Choreographer 简介三、Choreographer 源码解析四、APM 与 Choreographer五...

和你一起终身学习,这里是程序员 Android

本篇本文基本简介 Android 开发建设中的方面的知识要点,进行课外阅读本篇本文,您将赢得左右信息:
一、途径程电脑运行策略的本体论二、Choreographer 详细介绍三、Choreographer 源码解答四、APM 与 Choreographer五、MessageQueue 与 Choreographer六、移动制造厂商优化调整
本篇文章介紹了 App 開發者不长时间接受到其实在 Android Framework 效果图渲染线路中异常决定性的很多类 Choreographer。其中包括 Choreographer 的传入底色、Choreographer 的简洁、很多源码解析视频、Choreographer 与 MessageQueue、Choreographer 和 APM,已经平果手机生产商对于 Choreographer 的很多升级优化一个构想。Choreographer 的机遇,主耍是合作 Vsync ,给顶层 App 的突出保证有一个保持稳定的 Message 处理的时间窗口,也说是说 Vsync 即将到来的时会 ,软件用对 Vsync 数据无线信号定期的变动,来控住每一帧制图作业的时间窗口. 现下大地方移动是 60Hz 的自动清空率,也说是说 16.6ms 自动清空每次,软件因为合作频幕的自动清空概率,将 Vsync 的定期也设为为 16.6 ms,每台 16.6 ms , Vsync 数据无线信号重启 Choreographer 来做 App 的制图作业 ,这说是说机遇 Choreographer 的主耍效应. 熟知 Choreographer 还需要帮助到 App 开发管理者都清楚软件每一帧正常运行的基本性道理,也需要加重对 Message、Handler、Looper、MessageQueue、Measure、Layout、Draw 的认知

一、主线程运行机制的本质

在讲 Choreographer 之间,公司先理一会儿 Android 支线剧情程正常运作的实际上,就就 Message 的清理全过程,公司的几种运行,包含每一帧的草图大师渲染运行 ,基本上实现 Message 的的方式转发给支线剧情程的 MessageQueue ,MessageQueue 清理完讯息继读等下同一个讯息,下面图随时

MethodTrace 图示


Systrace 之Choreographer 机制


Systrace 图示


Systrace 之Choreographer 机制


1.演进

对接 Vsync 前一天的 Android 固件版本,渲图一帧关于的 Message ,在期间是没得区间的,上一帧画制完,下一帧的 Message 紧接下来着就开始了被除理。其实的话题正是,帧率不安全维持,也许 高也也许 低,不安全维持,方式图

MethodTrace 图示


Systrace 之Choreographer 机制


Systrace 图示


Systrace 之Choreographer 机制


相对 移动顾客说,稳固的的帧率算是好的体验感,比喻你玩王者农药荣耀游戏,相比较 fps 在 60 和 40 相互过频变换,移动顾客感更快的是稳固的在 50 fps 的实际情况。

所以 Android 的演进中,引入了 Vsync + TripleBuffer + Choreographer 的机制,其主要目的就是提供一个稳定的帧率输出机制,让软件层和硬件层可以以共同的频率一起工作。

2.引入 Choreographer

Choreographer 的传入,关键的是做好 Vsync ,给中上层 App 的渲图带来了一种相对稳定的 Message 操控方法的方式,也也还是 Vsync 已来的之时 ,整体成功完成对 Vsync 网络警报定期长的调节,来操纵每一帧画制操控方法的方式. 而说到为社东西 Vsync 定期长抉择是 16.6ms (60 fps) ,是因现今大区域收集的触摸屏还是 60Hz 的自动自动更新页面率,也也还是 16.6ms 自动自动更新页面一些,整体成了做好触摸屏的自动自动更新页面频点,将 Vsync 的定期长也制定为 16.6 ms,每间隔 16.6 ms ,Vsync 网络警报已来触发 Choreographer 来做 App 的画制操控方法 ,如何每位 Vsync 定期长适用都能渲图成功完成,这样适用的 fps 也还是 60 ,给用户组的凯时最新首页登录也还是是顺畅,这也还是传入 Choreographer 的关键的效应。


Systrace 之Choreographer 机制


然而现在运作 90Hz 刷新页面率霸屏的手机手机愈来愈越久,Vsync 的周期从 16.6ms 直到 11.1ms,上图示的运作要在更短的日期内结束,对性能参数的让也愈来愈越高,关键可不要看新的不卡体验性,90Hz 漫谈这篇软文

二、Choreographer 简介

Choreographer 扮成 Android 实时渲染路由协议中启下的脚色
  1. 承上:负责接收和处理 App 的各种更新消息和回调,等到 Vsync 到来的时候统一处理。比如集中处理 Input(主要是 Input 事件的处理) 、Animation(动画相关)、Traversal(包括 measure、layout、draw 等操作) ,判断卡顿掉帧情况,记录 CallBack 耗时等。
  2. 启下:负责请求和接收 Vsync 信号。接收 Vsync 事件回调(通过 FrameDisplayEventReceiver.onVsync );请求 Vsync(FrameDisplayEventReceiver.scheduleVsync) .

从上面可以看出来, Choreographer 担任的是一个工具人的角色,他之所以重要,是因为通过 Choreographer + SurfaceFlinger + Vsync + TripleBuffer 这一套从上到下的机制,保证了 Android App 可以以一个稳定的帧率运行(目前大部分是 60fps),减少帧率波动带来的不适感.

了解 Choreographer 还可以帮助 App 开发者知道程序每一帧运行的基本原理,也可以加深对 Message、Handler、Looper、MessageQueue、Measure、Layout、Draw 的理解 , 很多 APM工具也用到了 Choreographer( 利用 FrameCallback + FrameInfo ) + MessageQueue ( 利用 IdleHandler ) + Looper ( 设置自定义 MessageLogging) 这些组合拳,深入了解了这些之后,再去做优化,脑子里的思路会更清晰。

另外虽然画图是一个比较好的解释流程的好路子,但是我个人不是很喜欢画图,因为平时 Systrace 和 MethodTrace 用的比较多,Systrace 是按从左到右展示整个系统的运行情况的一个工具(包括 cpu、SurfaceFlinger、SystemServer、App 等关键进程),使用 SystraceMethodTrace也可以很方便地展示关键流程。当你对系统代码比较熟悉的时候,看 Systrace 就可以和手机运行的实际情况对应起来。所以下面的文章除了一些网图之外,其他的我会多以 Systrace 来展示.

1.从 Systrace 的角度来看 Choreogrepher 的工作流程

该图以翻转小米5手机win7桌面为好例子,你们先看看子从左到右翻转小米5手机win7桌面的这个完整性的加载图(App 进度),需要遇到 Systrace 中从左到右,每这个黄绿色的帧都透露一帧,透露最中你们需要小米5手电脑上遇到的画质
  1. 图中每一个灰色的条和白色的条宽度是一个 Vsync 的时间,也就是 16.6ms
  2. 每一帧处理的流程:接收到 Vsync 信号回调-> UI Thread –> RenderThread –> SurfaceFlinger(图中未显示)
  3. UI Thread 和 RenderThread 就可以完成 App 一帧的渲染,渲染完的 Buffer 抛给 SurfaceFlinger 去合成,然后我们就可以在屏幕上看到这一帧了
  4. 可以看到桌面滑动的每一帧耗时都很短(Ui Thread 耗时 + RenderThread 耗时),但是由于 Vsync 的存在,每一帧都会等到 Vsync 才会去做处理


Systrace 之Choreographer 机制


产生了上边这种整个的的概念,我门将 UI Thread 的每一帧变成来讲,一下 Choreogrepher 的地位并且 Choreogrepher 是怎们进行每一帧的


Systrace 之Choreographer 机制


2.Choreographer 的工作流程

  1. Choreographer 初始化初始化 FrameHandler ,绑定 Looper初始化 FrameDisplayEventReceiver ,与 SurfaceFlinger 建立通凯时最新首页登录于接收和请求 Vsync初始化 CallBackQueues
  2. SurfaceFlinger 的 appEventThread 唤醒发送 Vsync ,Choreographer 回调 FrameDisplayEventReceiver.onVsync , 进入 SurfaceFlinger 的主处理函数 doFrame
  3. Choreographer.doFrame 计算掉帧逻辑
  4. Choreographer.doFrame 处理 Choreographer 的第一个 callback : input
  5. Choreographer.doFrame 处理 Choreographer 的第二个 callback : animation
  6. Choreographer.doFrame 处理 Choreographer 的第三个 callback : insets animation
  7. Choreographer.doFrame 处理 Choreographer 的第四个 callback : traversaltraversal-draw 中 UIThread 与 RenderThread 同步数据
  8. Choreographer.doFrame 处理 Choreographer 的第五个 callback : commit
  9. RenderThread 处理绘制数据,真正进行渲染
  10. 将渲染好的 Buffer swap 给 SurfaceFlinger 进行合成

第一步初始化完成后,后续就会在步骤 2-9 之间循环

一起也附上这一帧所对应着的 MethodTrace(在这阅读一番就可以了,现在会起简要的大图)


Systrace 之Choreographer 机制


下列我国就从源码的视场角,看两下关键的达到

三、Choreographer 源码解析

接着从源码的视场角来简单的看说一下下,源码只摘抄了个位置决定性的思想,许多的思想则被筛选,额外 Native 个位置与 SurfaceFlinger 交互式的个位置也无纳入,不能从文中的关键性,有感兴趣的就可以本人去跟说一下下。

1. Choreographer 的初始化

  • Choreographer 的单例初始化
// Thread local storage for the choreographer.private static final ThreadLocal sThreadInstance = new ThreadLocal() { @Override protected Choreographer initialValue() { // 获取当前线程的 Looper Looper looper = Looper.myLooper(); ...... // 构造 Choreographer 对象 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\. 初始化 FrameHandler mHandler = new FrameHandler(looper); // 2\. 初始化 DisplayEventReceiver mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper, vsyncSource) : null; mLastFrameTimeNanos = Long.MIN_VALUE; mFrameIntervalNanos = (long)(1000000000 / getRefreshRate()); //3\. 初始化 CallbacksQueues mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1]; for (int i = 0; i <= CALLBACK_LAST; i++) { mCallbackQueues[i] = new CallbackQueue(); } ......}
  • FrameHandler
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://请求 Vsync  doScheduleVsync(); break; case MSG_DO_SCHEDULE_CALLBACK://处理 Callback doScheduleCallback(msg.arg1); break; } }}

2. Choreographer 初始化链

在 Activity 开机期间,履行完 onResume 后,会都会进行 Activity.makeVisible(),并且再都会进行到 addView(), 逐一都会进行会进入到有以下的方法
ActivityThread.handleResumeActivity(IBinder, boolean, boolean, String) (android.app) -->WindowManagerImpl.addView(View, LayoutParams) (android.view)  -->WindowManagerGlobal.addView(View, LayoutParams, Display, Window) (android.view) -->ViewRootImpl.ViewRootImpl(Context, Display) (android.view) public ViewRootImpl(Context context, Display display) { ...... mChoreographer = Choreographer.getInstance(); ...... }

3.FrameDisplayEventReceiver 简介

Vsync 的注册的、申办、接收入几乎都是采用 FrameDisplayEventReceiver 这位类,,因此应该先简便解绍一点。 FrameDisplayEventReceiver 法定继承 DisplayEventReceiver , 有三非常根本的具体方法
  1. onVsync – Vsync 信号回调
  2. run – 执行 doFrame
  3. scheduleVsync – 请求 Vsync 信号
private final class FrameDisplayEventReceiver extends DisplayEventReceiver implements Runnable { ...... @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); ...... }}

4.Choreographer 中 Vsync 的注册

从接下的数学函数跳转栈可能遇到,Choreographer 的实物类 FrameDisplayEventReceiver.onVsync 责任发送到 Vsync 回调函数,通知函 UIThread 完成数据源治理 。那样 FrameDisplayEventReceiver 是按照一些 的形式在 Vsync 警报来到的之后调整 onVsync 呢?原因是 FrameDisplayEventReceiver 的缺省化的之后,然后按照侦听文件名称句柄的的形式,其分别的缺省化注意事项相应android/view/Choreographer.java
private Choreographer(Looper looper, int vsyncSource) { mLooper = looper; mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper, vsyncSource) : null; ......}
android/view/Choreographer.java
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) { super(looper, vsyncSource);}
android/view/DisplayEventReceiver.java
public DisplayEventReceiver(Looper looper, int vsyncSource) { ...... mMessageQueue = looper.getQueue(); mReceiverPtr = nativeInit(new WeakReference(this), mMessageQueue, vsyncSource);}
nativeInit 随后的编号是可不可以自已跟看,是可不可以较这篇本文和源码,根据内文相对较多,这儿华祥苑茗茶小编就细写了(//www.jianshu.com/p/304f56f5d486) , 随后解读好这方面的思维模式后,会在其次的本文更行。简略我认为,FrameDisplayEventReceiver 的原始化环节中,实现 BitTube(实际是一名 socket pair),来信息传递和重定向 Vsync 案例,当 SurfaceFlinger 发送到到 Vsync 案例往后,实现 appEventThread 将你这个案例实现 BitTube 发送到 DisplayEventDispatcher ,DisplayEventDispatcher 实现 BitTube 的发送到端监视到 Vsync 案例往后,乖离率指标 Choreographer.FrameDisplayEventReceiver.onVsync ,促发就开始一帧的画制,方式图


Systrace 之Choreographer 机制


5.Choreographer 处理一帧的逻辑

Choreographer 整理画制的道理关键在 Choreographer.doFrame 函数公式中,从如图可以看看,FrameDisplayEventReceiver.onVsync post 了自身,其 run 的方式会直接取用了 doFrame 開始一帧的道理整理android/view/Choreographer.java
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);}public void run() { mHavePendingVsync = false; doFrame(mTimestampNanos, mFrame);}
doFrame 指数函数主耍做中间几套事
  1. 计算掉帧逻辑
  2. 记录帧绘制信息
  3. 执行 CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_INSETS_ANIMATION、CALLBACK_TRAVERSAL、CALLBACK_COMMIT

6.计算掉帧逻辑

void doFrame(long frameTimeNanos, int frame) { final long startNanos; synchronized (mLock) { ...... long intendedFrameTimeNanos = frameTimeNanos; startNanos = System.nanoTime(); final long jitterNanos = startNanos - frameTimeNanos; if (jitterNanos >= mFrameIntervalNanos) { final long skippedFrames = jitterNanos / mFrameIntervalNanos; if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) { Log.i(TAG, "Skipped " + skippedFrames + " frames!  " + "The application may be doing too much work on its main thread."); } } ...... } ......}
Choreographer.doFrame 的掉帧测量相对比较容易,从如图能见到,Vsync 警报即将来临的时期会标志2个 start_time ,履行 doFrame 的时期标志2个 end_time ,这2个时差只是 Vsync 操作时延,也只是掉帧


Systrace 之Choreographer 机制


咱们以 Systrace 的掉帧的真正环境来说掉帧的算思想


Systrace 之Choreographer 机制

image


现在想要考虑的是,这样技巧换算的掉帧,是前一帧的掉帧事情,而不再是这一帧的掉帧事情,一个换算技巧是有瑕疵的,会影响有的掉帧就没有被换算到

7.记录帧绘制信息

Choreographer 中 FrameInfo 来担负数据信息帧的绘出数据信息,doFrame 执行命令的时刻,会把每段个关键性连接点的绘出事件数据信息成功,.我便用 dumpsys gfxinfo 就行观察到。自然 Choreographer 只 数据信息了一部电影分,余下的这部份在 hwui 那块来数据信息。从 FrameInfo 以上标识就能能可以看出记录卡的信息内容,前边我门看 dumpsys gfxinfo 的之前数据库即使决定该来排列方式的
// Various flags set to provide extra metadata about the current frameprivate static final int FLAGS = 0;// Is this the first-draw following a window layout?public static final long FLAG_WINDOW_LAYOUT_CHANGED = 1;// A renderer associated with just a Surface, not with a ViewRootImpl instance.public static final long FLAG_SURFACE_CANVAS = 1 << 2;@LongDef(flag = true, value = { FLAG_WINDOW_LAYOUT_CHANGED, FLAG_SURFACE_CANVAS })@Retention(RetentionPolicy.SOURCE)public @interface FrameInfoFlags {}// The intended vsync time, unadjusted by jitterprivate static final int INTENDED_VSYNC = 1;// Jitter-adjusted vsync time, this is what was used as input into the// animation & drawing systemprivate static final int VSYNC = 2;// The time of the oldest input eventprivate static final int OLDEST_INPUT_EVENT = 3;// The time of the newest input eventprivate static final int NEWEST_INPUT_EVENT = 4;// When input event handling startedprivate static final int HANDLE_INPUT_START = 5;// When animation evaluations startedprivate static final int ANIMATION_START = 6;// When ViewRootImpl#performTraversals() startedprivate static final int PERFORM_TRAVERSALS_START = 7;// When View:draw() startedprivate static final int DRAW_START = 8;
doFrame 变量记录表从 Vsync time 到 markPerformTraversalsStart 的准确时间
void doFrame(long frameTimeNanos, int frame) { ...... mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos); // 处理 CALLBACK_INPUT Callbacks  mFrameInfo.markInputHandlingStart(); // 处理 CALLBACK_ANIMATION Callbacks mFrameInfo.markAnimationsStart(); // 处理 CALLBACK_INSETS_ANIMATION Callbacks // 处理 CALLBACK_TRAVERSAL Callbacks mFrameInfo.markPerformTraversalsStart(); // 处理 CALLBACK_COMMIT Callbacks ......}

8.执行 Callbacks

void doFrame(long frameTimeNanos, int frame) { ...... // 处理 CALLBACK_INPUT Callbacks  doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos); // 处理 CALLBACK_ANIMATION Callbacks doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos); // 处理 CALLBACK_INSETS_ANIMATION Callbacks doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos); // 处理 CALLBACK_TRAVERSAL Callbacks doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos); // 处理 CALLBACK_COMMIT Callbacks doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos); ......}

Input 回调调用栈

input callback 一般是执行 ViewRootImpl.ConsumeBatchedInputRunnable

android/view/ViewRootImpl.java
final class ConsumeBatchedInputRunnable implements Runnable { @Override public void run() { doConsumeBatchedInput(mChoreographer.getFrameTimeNanos()); }}void doConsumeBatchedInput(long frameTimeNanos) { if (mConsumeBatchedInputScheduled) { mConsumeBatchedInputScheduled = false; if (mInputEventReceiver != null) { if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos) && frameTimeNanos != -1) { scheduleConsumeBatchedInput(); } } doProcessInputEvents(); }}
Input 时刻经由操作,决定会传染给 DecorView 的 dispatchTouchEvent,这就达到你们感兴趣的 Input 事情分派


Systrace 之Choreographer 机制


Animation 回调调用栈

普通当我们交往的多的是加载 View.postOnAnimation 的之时 ,会利用到 CALLBACK_ANIMATION
public void postOnAnimation(Runnable action) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { attachInfo.mViewRootImpl.mChoreographer.postCallback( Choreographer.CALLBACK_ANIMATION, action, null); } else { // Postpone the runnable until we know // on which thread it needs to run. getRunQueue().post(action); }}
所以般是什么样的的时候调整涉及到 View.postOnAnimation 呢,我读取了一份图,用户 可以我自己去看一会,触碰较多的应当是 startScroll,Fling 这一种操作的


Systrace 之Choreographer 机制

image


其启用栈会根据其 post 的相关内容,下文是桌面图标滚动条松手后会的 fling 动画电影。


Systrace 之Choreographer 机制


此外当我们的 Choreographer 的 FrameCallback 也是用的 CALLBACK_ANIMATION
public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) { if (callback == null) { throw new IllegalArgumentException("callback must not be null"); } postCallbackDelayedInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN, delayMillis);}

Traversal 调用栈

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 removemHandler.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(); }}

doTraversal 的 TraceView 示例


Systrace 之Choreographer 机制

image


9. 下一帧的 Vsync 请求

由动漫视频、拖动、Fling 这实操的会存在,大家必须要 一款 重复的、比较稳定的帧率读取策略。这就有关到了 Vsync 的明确提出形式逻辑,在重复的实操,譬如动漫视频、拖动、Fling 这时分下,每一帧的 doFrame 的时分,还会依据时分促发下一款 Vsync 的注册,这样的话大家就是可以刷出重复的 Vsync 信号灯。看下文的 scheduleTraversals 取用栈(scheduleTraversals 中会打断 Vsync 請求)
Systrace 之Choreographer 机制

image.我更了解自己的 invalidate 和 requestLayout 会促发 Vsync 表现明确提出


各位下方以 Animation 举例,看着 Animation 是是怎样的驱程下一两个 Vsync ,来快速创新频幕的

10. ObjectAnimator 动画驱动逻辑

android/animation/ObjectAnimator.java
public void start() {super.start();}
android/animation/ValueAnimator.java
 private void start(boolean playBackwards) { ...... addAnimationCallback(0); // 动画 start 的时候添加 Animation Callback  ......}private void addAnimationCallback(long delay) { ...... getAnimationHandler().addAnimationFrameCallback(this, delay);}
android/animation/AnimationHandler.java
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) { if (mAnimationCallbacks.size() == 0) { // post FrameCallback getProvider().postFrameCallback(mFrameCallback); } ......}// 这里的 mFrameCallback 回调 doFrame,里面 post了自己private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() { @Override public void doFrame(long frameTimeNanos) { doAnimationFrame(getProvider().getFrameTime()); if (mAnimationCallbacks.size() > 0) { // post 自己 getProvider().postFrameCallback(this); } }};
都会进行 postFrameCallback 会靠近 mChoreographer.postFrameCallback ,此地就是捕获 Choreographer 的 Vsync 請求逻辑思维android/animation/AnimationHandler.java
public void postFrameCallback(Choreographer.FrameCallback callback) { mChoreographer.postFrameCallback(callback);}
android/view/Choreographer.java
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) {// 请求 Vsync scheduleFrameLocked ->scheduleVsyncLocked-> mDisplayEventReceiver.scheduleVsync ->nativeScheduleVsyncscheduleFrameLocked(now);} else {Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);msg.arg1 = callbackType;msg.setAsynchronous(true);mHandler.sendMessageAtTime(msg, dueTime);}}}

通过上面的 Animation.start 设置,利用了 Choreographer.FrameCallback 接口,每一帧都去请求下一个 Vsync动画过程中一帧的 TraceView 示例


Systrace 之Choreographer 机制


11. 源码小结

  1. Choreographer 是线程单例的,而且必须要和一个 Looper 绑定,因为其内部有一个 Handler 需要和 Looper 绑定,一般是 App 主线程的 Looper 绑定
  2. DisplayEventReceiver是一个 abstract class,其 JNI 的代码部分会创建一个IDisplayEventConnection 的 Vsync 监听者对象。这样,来自 AppEventThread 的 VSYNC 中断信号就可以传递给 Choreographer 对象了。当 Vsync 信号到来时,DisplayEventReceiver 的 onVsync 函数将被调用。
  3. DisplayEventReceiver还有一个 scheduleVsync 函数。当应用需要绘制UI时,将首先申请一次 Vsync 中断,然后再在中断处理的 onVsync 函数去进行绘制。
  4. Choreographer 定义了一个 FrameCallback interface,每当 Vsync 到来时,其 doFrame 函数将被调用。这个接口对 Android Animation 的实现起了很大的帮助作用。以前都是自己控制时间,现在终于有了固定的时间中断。
  5. Choreographer 的主要功能是,当收到 Vsync 信号时,去调用使用者通过 postCallback 设置的回调函数。目前一共定义了五种类型的回调,它们分别是:
  • 1 . CALLBACK_INPUT : 处理输入事件处理有关
  • 2 . CALLBACK_ANIMATION : 处理 Animation 的处理有关
  • 3 . CALLBACK_INSETS_ANIMATION : 处理 Insets Animation 的相关回调
  • 4 . CALLBACK_TRAVERSAL : 处理和 UI 等控件绘制有关
  • 5 . CALLBACK_COMMIT : 处理 Commit 相关回调
  1. ListView 的 Item 初始化(obtain\setup) 会在 input 里面也会在 animation 里面,这取决于
  2. CALLBACK_INPUTCALLBACK_ANIMATION 会修改 view 的属性,所以要先与 CALLBACK_TRAVERSAL 执行

四、APM 与 Choreographer

主要是因为 Choreographer 的地点,诸多效能监测的的措施基本上借助 Choreographer 来做的,抛开预装软件卸载的掉帧换算,Choreographer 提供了的 FrameCallback 和 FrameInfo 都给 App 露出了主板接口,让 App 開發者能够 进行这样措施监测自 App 的效能,这其中实用的措施下列:
  1. 利用 FrameCallback 的 doFrame 回调
  2. 利用 FrameInfo 进行监控使用 :adb shell dumpsys gfxinfo framestats示例 :adb shell dumpsys gfxinfo com.meizu.flyme.launcher framestats
  3. 利用 SurfaceFlinger 进行监控使用 :adb shell dumpsys SurfaceFlinger –latency示例 :adb shell dumpsys SurfaceFlinger –latency com.meizu.flyme.launcher/com.meizu.flyme.launcher.Launcher#0
  4. 利用 SurfaceFlinger PageFlip 机制进行监控使用 : adb service call SurfaceFlinger 1013备注:需要系统权限
  5. Choreographer 自身的掉帧计算逻辑
  6. BlockCanary 基于 Looper 的性能监控

1.利用 FrameCallback 的 doFrame 回调

FrameCallback 接头
public interface FrameCallback {public void doFrame(long frameTimeNanos);}
音频接口适用
Choreographer.getInstance().postFrameCallback(youOwnFrameCallback );
主板接口外理
public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) { ...... postCallbackDelayedInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN, delayMillis);}
TinyDancer 便是用到了这的办法来算起 FPS (//github.com/friendlyrobotnyc/TinyDancer)

2. 利用 FrameInfo 进行监控

adb shell dumpsys gfxinfo  Window: StatusBarStats since: 17990256398nsTotal frames rendered: 1562Janky frames: 361 (23.11%)50th percentile: 6ms90th percentile: 23ms95th percentile: 36ms99th percentile: 101msNumber Missed Vsync: 33Number High input latency: 683Number Slow UI thread: 273Number Slow bitmap uploads: 8Number Slow issue draw commands: 18Number Frame deadline missed: 287HISTOGRAM: 5ms=670 6ms=128 7ms=84 8ms=63 9ms=38 10ms=23 11ms=21 12ms=20 13ms=25 14ms=39 15ms=65 16ms=36 17ms=51 18ms=37 19ms=41 20ms=20 21ms=19 22ms=18 23ms=15 24ms=14 25ms=8 26ms=4 27ms=6 28ms=3 29ms=4 30ms=2 31ms=2 32ms=6 34ms=12 36ms=10 38ms=9 40ms=3 42ms=4 44ms=5 46ms=8 48ms=6 53ms=6 57ms=4 61ms=1 65ms=0 69ms=2 73ms=2 77ms=3 81ms=4 85ms=1 89ms=2 93ms=0 97ms=2 101ms=1 105ms=1 109ms=1 113ms=1 117ms=1 121ms=2 125ms=1 129ms=0 133ms=1 150ms=2 200ms=3 250ms=0 300ms=1 350ms=1 400ms=0 450ms=0 500ms=0 550ms=0 600ms=0 650ms=0 ---PROFILEDATA---Flags,IntendedVsync,Vsync,OldestInputEvent,NewestInputEvent,HandleInputStart,AnimationStart,PerformTraversalsStart,DrawStart,SyncQueued,SyncStart,IssueDrawCommandsStart,SwapBuffers,FrameCompleted,DequeueBufferDuration,QueueBufferDuration,0,10158314881426,10158314881426,9223372036854775807,0,10158315693363,10158315760759,10158315769821,10158316032165,10158316627842,10158316838988,10158318055915,10158320387269,10158321770654,428000,773000,0,10158332036261,10158332036261,9223372036854775807,0,10158332799196,10158332868519,10158332877269,10158333137738,10158333780654,10158333993206,10158335078467,10158337689561,10158339307061,474000,885000,0,10158348665353,10158348665353,9223372036854775807,0,10158349710238,10158349773102,10158349780863,10158350405863,10158351135967,10158351360446,10158352300863,10158354305654,10158355814509,471000,836000,0,10158365296729,10158365296729,9223372036854775807,0,10158365782373,10158365821019,10158365825238,10158365975290,10158366547946,10158366687217,10158367240706,10158368429248,10158369291852,269000,476000,

3. 利用 SurfaceFlinger 进行监控

ftp命令解释清楚:
  1. 数据的单位是纳秒,时间是以开机时间为起始点
  2. 每一次的命令都会得到128行的帧相关的数据
信息:
  1. 第一行数据,表示刷新的时间间隔refresh_period
  2. 第1列:这一部分的数据表示应用程序绘制图像的时间点
  3. 第2列:在SF(软件)将帧提交给H/W(硬件)绘制之前的垂直同步时间,也就是每帧绘制完提交到硬件的时间戳,该列就是垂直同步的时间戳
  4. 第3列:在SF将帧提交给H/W的时间点,算是H/W接受完SF发来数据的时间点,绘制完成的时间点。

掉帧 jank 计算

每几行都行以顺利通过以下的公式计算得到了个值,该值是个规格,各位叫作jankflag,如果你目前行的jankflag与上几行的jankflag会出现增加,那些就叫掉帧ceil((C - A) / refresh-period)

4. 利用 SurfaceFlinger PageFlip 机制进行监控

 Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();                data.writeInterfaceToken("android.ui.ISurfaceComposer");mFlinger.transact(1013, data, reply, 0);final int pageFlipCount = reply.readInt();final long now = System.nanoTime();final int frames = pageFlipCount - mLastPageFlipCount;final long duration = now - mLastUpdateTime;mFps = (float) (frames * 1e9 / duration);mLastPageFlipCount = pageFlipCount;mLastUpdateTime = now;reply.recycle();data.recycle();

5. Choreographer 自身的掉帧计算逻辑

SKIPPED_FRAME_WARNING_LIMIT 同意为30 , 由 debug.choreographer.skipwarning 这家功能操纵
 if (jitterNanos >= mFrameIntervalNanos) { final long skippedFrames = jitterNanos / mFrameIntervalNanos; if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) { Log.i(TAG, "Skipped " + skippedFrames + " frames!  " + "The application may be doing too much work on its main thread."); }}

6. BlockCanary

Blockcanary 来计算做特点网络监控视频安全使用的是 Looper 的小道消息制度化,实现对 MessageQueue 中任一家 Message 的上下进行数据,打过网络监控视频特点的的android/os/Looper.java
public static void loop() { ... for (;;) { ... // This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } msg.target.dispatchMessage(msg); if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } ... }}

五、MessageQueue 与 Choreographer

常说的的异步信息提醒并不是便是也许的,.我的也可按照 enqueueBarrier 往信息提醒链表中插入表格两个 Barrier,很链表中来连接时间段在一个 Barrier 时候的同部信息提醒也会被一个 Barrier 电话拦截住始终无法来连接,是直到.我的资源传参 removeBarrier 移除开一个 Barrier,而异步信息提醒则就没有不良影响,信息提醒默认设立便是同部信息提醒,除非是.我的资源传参了 Message 的 setAsynchronous,一个的方法是藏的。唯有在初期化 Handler 时按照因素锁定往一个 Handler 发送邮件的信息提醒是异步的,也许在 Handler 的 enqueueMessage 中都会资源传参 Message 的 setAsynchronous 设立信息提醒是异步的,从表面 Handler.enqueueMessage 的二维码中也可看清。所说的异步发发发消息,实际上 不过同一个功能,正是在设有 Barrier 时仍能否不在 Barrier 的决定被通常治理 ,若果找不到设有 Barrier,异步发发发消息就与数据同步发发发消息找不到不同于,能否按照 removeSyncBarrier 移除 Barrier

1. SyncBarrier 在 Choreographer 中使用的一个示例

scheduleTraversals 的之时 postSyncBarrier
void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; //为了提高优先级,先 postSyncBarrier mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); }}
doTraversal 的之时 removeSyncBarrier
 void doTraversal() { if (mTraversalScheduled) { mTraversalScheduled = false; // 这里把 SyncBarrier removemHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); // 真正开始 performTraversals(); }}
Choreographer post Message 的的时候,会把一些小道消息设为 Asynchronous ,这个Choreographer 中的一些 Message 的优先的级就特别高,
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);msg.arg1 = callbackType;msg.setAsynchronous(true);mHandler.sendMessageAtTime(msg, dueTime);

六、厂商优化

控制系统生产厂家随着是会直观性降重源码,也使用这管理方面的社区便利店,做以下作用和SEO,当然随着加密的方面,码还是会直观性放端上来了,我是会大约说以下指导思想,感有趣的是会私自探讨

1.移动事件优化

Choreographer 自身是找不到 input 信息的, 不过了更改源码以后,input 信息能否会直接给到 Choreographer 这儿, 上了以下 Input 信息,Choreographer 就能否做其他事项,词有说晚到回应,没去等 Vsync

2.后台动画优化

当其中一个 Android App 退到页面后续,主要他如果没有被杀灭,这样的话他做哪个时候各位都不要再诧异,如果这可是 Android。有的 App 退到页面后续我还在连续调节 Choreographer 中的 Animation Callback,而这是 Callback 的完成完全性是无作用的,另外消费者还不了解到道,并且对 cpu 的负载是比高的。那么在 Choreographer 中会而对这些现象做系统优化,明令禁止不达到先决条件的 App 在后台管理再继续没有用的作业


Systrace 之Choreographer 机制

image


3. 帧绘制优化

和移动式时间真相优化提升不一样,鉴于到了 Input 时间真相的信息查询,在部分场所下我国能能通知格式 SurfaceFlinger 只用取等待中 Vsync 直观做人工进行

4.应用启动优化

各位前加说,核心程的很多运行均是享有 Message 的 ,如若许多 运行,非很重要性的 Message 被布局进了序列后边,但是对这里运行有影响力;而确认全新布局 MessageQueue,在app运行的时刻,把运行一些的很重要性的运行 Message 放进序列前加,来充当快速运行进程的目的

5.高帧率优化

90 fps 的智能手机手机里 , Vsync 间格从 16.6ms 转变成了 11.1ms ,这面临了非常大的耐腐蚀性和输出功率挑衅,怎么样才能在一帧内完全渲图的这个必要操作方法,是智能手机手机经销商一定要心思和seo的地点:
  1. 超级 App 的性能表现以及优化
  2. 游戏高帧率合作
  3. 90 fps 和 60 fps 相互切换的逻辑原文作者:Gracker
阅读答案链接搜索://androidperformance.com/2019/10/22/Android-Choreographer/

(正文已结束了)

免责声明及提醒:此文内容为本网所转载企业宣传资讯,该相关信息仅为宣传及传递更多信息之目的,不代表本网站观点,文章真实性请浏览者慎重核实!任何投资加盟均有风险,提醒广大民众投资需谨慎!

返回凯时最新首页登录
Copyright 2002-2019 凯时最新首页登录时尚网 版权所有 本网拒绝一切非法行为 欢迎监督举报 如有错误信息 欢迎纠正