Flutter与Vsync信号

2020-10-20  本文已影响0人  Wi1ls努力努力再努力

在FlutterEngine的构造函数的调用链中,会执行startInitialization(Context,Settings)@FlutterLoader.java

public void startInitialization(Context applicationContext, Settings settings){
  ...
  VsyncWaiter.getInstance((WindowManager)applicationContext.getSystemService(Context.WINDOW_SERVICE)).init();
  ...
}


@VsyncWaiter.java
private final FlutterJNI.AsyncWaitForVsyncDelegate asyncWaitForVsyncDelegate = new FlutterJNI.AsyncWaitForVsyncDelegate(){
  public void asyncWaitForVsync(long cookie){
    Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback(){
      public void doFrame(long frameTimeNanos){
        ...
        FlutterJNI.nativeOnVsync(frameTimeNanos, frameTimeNanos+refreshPeriodNanos, cookie);
      }
    });
  }
}

public void init(){
  FlutterJNI.setAsyncWaitForVsyncDelegate(asyncWaitForVsyncDelegate);
  ...
}

来看FlutterJNI对于这个asyncWaitForVsyncDelegate的使用

@FlutterJNI.java
//Called by native
private static void asyncWaitForVsync(final long cookie){
  if(asyncWaitForVsyncDelegate != null){
    asyncWaitForVsyncDelegate.asyncWaitForVsync(cookie);
  }
}

public static native void nativeOnVsync(long frameTimeNanos, long frameTargetTimeNanos, long cookie);

上面对于asyncWaitForVsync()的那句注释Calledbynative是Flutter原始注释,说明这个方法会在某个native节点进行调用。
该native方法是注册啊vsync_wait_android.cc中[engine源码],对应的方法为onNativeVsync()
现在假定它被调用了。

//./shell/platform/android/vsync_waiter_android.cc
void VsyncWaiterAndroid::OnNativeVsync(JNIEnv* env, jclass jcaller, jlong frameTimeNanos, jlong frameTargetTimeNanos, jlong java_baton){
  ...
  ConsumePendingCallback(java_baton, frame_time, target_time);
}

void VsyncWaiterAndroid::ConsumePendingCallback(jlong java_baton, fml::TimePoint frame_start_time, fml::TimePoint frame_target_time){
  ...
  //VsyncWaiter类
  shared_this->FireCallback(frame_start_time, frame_target_time);
}

//vsync_waiter.cc
void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time, fml_TimePoint frame_target_time){
  Callback callback=std::move(callback_);
  ...
  task_runners.GetUITaskRunner()->PostTakForTime(
    [callback, flow_identifier, frame_start_time, frame_start_time](){
      callback(frame_start_time, frame_target_time);
    },frame_start_time);
)
}

上面就是将callback 抛到UI线程进行执行,callback_是在VsyncWaiter::AsyncWaitForVsync(Callback)中进行赋值,而该函数在animatior.cc中进行调用

//animatior.cc
void Animator::AwaitVSync(){
  waiter_->AsyncWaitForVsync([self=weak_factory_.GetWeakPtr()](fml::TimePoint frame_start_time, fml::TimePoint frame_target_time){
    //这里是self就是animator对象
    if(self){
      if(self->CanReuseLastLayerTree()){
        self->DrawLastLayerTree();
      }else{
        self->BeginFrame(frame_start_time, frame_target_time);
      }
    }
  });
AwaitVsync();
}

这里需要提一句,Animator::AwaitVsync()是在由Animator:RequestFrame()调用,而后者是在Engine::ScheduleFrame()调用。

这里的AwaitVsync()指向VsyncWaiterAndroid::AwaitVsync();

//vsync_waiter_android.cc
void VsyncWaiterAndroid::AwaitSync(){
  ...
  task_runners_.GetPlatformTaskRunner()->PostTask([java_baton](){
    JNIEnv* env = fml::jni::AttachCurrentThread();
    //从该类不难得出,该方法反射调用asyncWaitForVsync()@FluuterJNI.java,即我们分析的源头。
    env->CallStaicVoidMethod(g_vsync_waiter_class->obj(), g_async_wait_for_vsync_method_, java_baton);
  });
}

现在有一环跑通了,从Engine::.scheduleFrame()到Animator::RequestFrame()到Animator::AwaitVsync()其实就是注册这个VSYNC回调的过程,而每次执行完self->DrawLastLayerTree()或self->BeginFrame()后,又重新注册vsync,即每次VSYNC到来(不发生掉帧)都会进行一次回调Animator::DrawLastLayerTree()或Animator::BeginFrame(),Animator::DrawLastLayerTree()就是绘制上一次的视图,现在重点看Animator::BeginFrame();

//animator.cc
void Animator::BeginFrame(fml::TimePoint frame_start_time, fml::TimePoint frame_target_time){
  ...
  //delegate_为shell.cc对象
  delegate_.onAnimatorBeginFrame(last_begin_frame_time_);
}

//shell.cc
void Shell::OnAnimatorBeginFrame(fml::TimePoint frame_time){
  engine_->BeginFrame(frame_time); 
}

//engine.cc
void Engine::BeginFrame(fml::TimePoint frame_time){
  runtime_control_->BeginFrame(frame_time);
}

//runtime_controller.cc
bool RuntimeController::BeginFrame(fml::TimePoint frame_time){
  window->BeginFrame(frame_time);
}

//window.cc
void Window::BeginFrame(fml::TimePoint frameTime){
  //该反射会调用onBeginFrame()@window.dart
  tonic::DartInvokeFiled(library_.value(), "_beginFrame",{Dart_NewInteger(microseconds),}));
  //执行microtask
  UIDartState::Current()->FlushMicrotaskNow();
  //该反射会调用onDrawFrame()@window.dart
  tonic::DartInvokeField(library_.value(),"_drawFrame",{})';
}

可以看到microtask位于beginFrame和drawFrame之间,耗时会影响ui绘制。

//hooks.dart
@pragma('vm:entry-point')
void _beginFrame(int microseconds){
  _invoke1<Duration>(window.onBeginFrame, window._onBeginFrameZone, Duration(microseconds:microseconds));
}

@pragma('vm:entry-point')
void _drawFrame(){
  _invoke(window.onDrawFrame, window._onDrawFrameZone);
}

window.onBeginFrame与onDrawFrame在ScheduleBinding(binding.dart中注册),在flutter_run_app_analyze中已经有提及了,

//scheduler/binding.dart
void _handleBeginFrame(Duration rawTimeStamp){
  handleBeginFrame(rawTimeStamp);
}

void _handleDrawFrame(){
  handleDrawFrame(rawTimeStamp);
}

关于handleBeginFrame()与handleDrawFrame()另外其文章分析。

上一篇 下一篇

猜你喜欢

热点阅读