目录

ArkUI页面动画卡顿掉帧

问题现象

动画运行时存在不流畅、掉帧的现象。

背景知识

问题定位

  1. 使用Smartperf抓取动画卡顿场景的Trace信息,找到查看render_service泳道中的H:PreferredFrameRate子泳道确认问题场景屏幕刷新率,如下图中屏幕刷新率为120Hz,则Vsync信号周期为8.3ms。

  2. 找到render_service泳道中的render_service子泳道,框选问题场景中的Trace信息确认该过程绘制帧率,如下图为25.6fps,绘制帧率远小于屏幕刷新率。根据H:ReceiveVsync关键字在Slices页中查看相关Trace信息,发现render_service线程在接收Vsync信号处理时耗时最多为7.6ms,未超出8.3ms,因此render_service未出现卡顿,推测是应用进程问题导致卡顿丢帧。

  3. 找到应用主线程泳道,根据H:MarshRSTransactionData关键字查看应用发送绘制相关数据给图形服务进程的频率,如果发送绘制指令相关数据的周期大于Vsync信号周期,则是应用进程发送绘制指令较慢导致动画卡顿。如下图中发送绘制指令相关数据周期为42.9ms左右,远大于8.3ms,需要排查应用进程发送绘制指令较慢的原因。

  4. 分析H:MarshRSTransactionData关键字间应用进程Trace信息和运行状态确定应用进程发送绘制指令较慢的原因,具体如下:
    • 情况一:
      1. 如果在应用主线程两次发送绘制指令间,主线程大多数时间处于sleeping状态、应用接收Vsync信号处理耗时未大于8.3ms,如下图所示,该情况下可能是应用进程中执行动画的组件渲染周期较长,应用送帧较少导致动画卡顿丢帧。

      2. 使用ArkUI Inspector确认执行动画的组件的id为317,在Trace中搜索执行该组件渲染任务的Trace关键字H:FrameNode[Canvas][id:317]::RenderTask,可看到执行该组件渲染任务的周期为42.9ms左右,远大于8.3ms,可知应用动画本身帧率较低,送帧较少导致卡顿丢帧现象。

    • 情况二:
      1. 如果在应用主线程两次发送绘制指令间,应用有执行耗时操作,如下图所示中在Napi complete部分耗时长(达到44ms),该部分是由于complete回调函数或await之后业务逻辑耗时较多导致,需要排查JsGetComponent执行后的业务代码。

      2. 使用DevEco Profiler Time分析Napi complete耗时原因,从Callstack泳道中的应用主线程泳道中可看到该部分耗时主要集中在应用so文件业务代码部分。

    • 情况三:
      1. 如果在应用主线程两次发送绘制指令间,主线程大多数时间处于running状态、应用接收Vsync信号处理耗时大于8.3ms,如下图所示,该情况下是应用进程执行耗时操作导致动画卡顿丢帧。

      2. 排查上图中Trace点H:ReceiveVsync下Trace信息,发现耗时较长为H:RSModifier::Draw,推测该应用是通过不断修改组件的属性值,触发绘制来实现动画效果,但没有看到组件相关的Trace关键字,因此使用Ark Inspector查看应用当前页面的组件树,发现该页面通过XComponent组件渲染显示。

      3. 使用DevEco Profiler Time分析应用绘制时的大致流程,得知其在动画启动时首先执行了onDrawChild函数,在Canvas上绘制显示的内容,然后调用flush2Surface函数,从Canvas中读取数据传递到XComponent组件渲染,之后则不断在Canvas上绘制当前页面,从Canvas中读取数据传递给XComponent组件更新当前页面的翻页过程状态。

        从上图中可看到在动画执行过程中,耗时主要在从Canvas中读取数据(12ms),超出了Vsync信号周期(8.3ms),导致动画卡顿丢帧。

分析结论

ArkUI页面动画卡顿丢帧的原因有:

修改建议