flutter UI渲染源码解析之VSYNC注册过程(一)

flutter 是google推出的一套移动端高质量UI渲染框架,其引擎是自己的渲染引擎。
flutter 的UI渲染主要是两个线程在起作用:

UI线程:运行着UI Task Runner,是Flutter Engine用于执行Dart root isolate代码,将其转换为layer tree视图结构;处理页面元素的layout过程
Raster线程:该线程依然是在CPU上执行,处理layer tree并render子类对象,将其转换成为GPU命令并发送到GPU。

UI渲染概览


1.当需要渲染则会调用到Engine的ScheduleFrame()来注册VSYNC信号回调,一旦触发回调doFrame()执行完成后,便会移除回调方法,也就是说一次注册一次回调;
2.当需要再次绘制则需要重新调用到ScheduleFrame()方法,该方法的唯一重要参数regenerate_layer_tree决定在帧绘制过程是否需要重新生成layer tree,还是直接复用上一次的layer tree;
3.UI线程的绘制过程,最核心的是执行WidgetsBinding的drawFrame()方法,然后会创建layer tree视图树
再交由GPU Task Runner将layer tree提供的信息转化为平台可执行的GPU指令。

UI绘制核心工作

1)Vsync单注册模式:保证在一帧的时间窗口里UI线程只会生成一个layer tree发送给GPU线程,原理如下:

Animator中的信号量pending_frame_semaphore_用于控制不能连续频繁地调用Vsync请求,一次只能存在Vsync注册。 pending_frame_semaphore_初始值为1,在Animator::RequestFrame()消费信号会减1,当而后再次调用则会失败直接返回; Animator的BeginFrame()或者DrawLastLayerTree()方法会执行信号加1操作。

2)UI绘制最核心的方法是drawFrame(),包含以下几个过程:

Animate: 遍历transientCallbacks,执行动画回调方法;
Build: 对于dirty的元素会执行build构造,没有dirty元素则不会执行,对应于buildScope()
Layout: 计算渲染对象的大小和位置,对应于flushLayout(),这个过程可能会嵌套再调用build操作;
Compositing bits: 更新具有脏合成位的任何渲染对象, 对应于flushCompositingBits();
Paint: 将绘制命令记录到Layer, 对应于flushPaint();
Compositing: 将Compositing bits发送给GPU, 对应于compositeFrame();
Semantics: 编译渲染对象的语义,并将语义发送给操作系统, 对应于flushSemantics()。
UI线程的耗时从doFrame(frameTimeNanos)中的frameTimeNanos为起点,以小节Animator::Render()方法结束为终点, 并将结果保存到LayerTree的成员变量construction_time
,这便是UI线程的耗时时长。

vsync

UI是如何渲染到UI上的:

1.首先我们知道flutter的运行开始点是:

void main() {
  runApp(MyApp());
}

runApp需要传递的参数是widget,

void runApp(Widget app) {
  //创建WidgetsFlutterBinding的单利
  WidgetsFlutterBinding.ensureInitialized()
  //将widget attach到root中
    ..scheduleAttachRootWidget(app)
  //UI的渲染执行开始点
    ..scheduleWarmUpFrame();
}

下面是一系列的调用过程:

  • 1.scheduler/binding.dart #scheduleWarmUpFrame
void scheduleWarmUpFrame() {
 ...
    Timer.run(() {
      assert(_warmUpFrame);
      handleDrawFrame();
      resetEpoch();
      _warmUpFrame = false;
      if (hadScheduledFrame) 
        //继续调用
        scheduleFrame();
    });
...
  }
  • 2.scheduler/binding.dart #scheduleFrame
void scheduleFrame() {
    if (_hasScheduledFrame || !framesEnabled)
      return;
    assert(() {
      if (debugPrintScheduleFrameStacks)
        debugPrintStack(label: 'scheduleFrame() called. Current phase is $schedulerPhase.');
      return true;
    }());
    ensureFrameCallbacksRegistered();
//这里调用的了window的scheduleFrame方法。window.dart中的方法都是对应于window.cc中的方法。
    window.scheduleFrame();
    _hasScheduledFrame = true;
  }
  • 3.ui/widnow.dart #scheduleFrame
void scheduleFrame() native 'PlatformConfiguration_scheduleFrame';

window.ccRegisterNatives注册了与window.dart的关系

void Window::RegisterNatives(tonic::DartLibraryNatives* natives) {
  natives->Register({
      {"Window_defaultRouteName", DefaultRouteName, 1, true},
      //这里window#scheduleFrame调用的是ScheduleFrame
      {"Window_scheduleFrame", ScheduleFrame, 1, true},
      {"Window_sendPlatformMessage", _SendPlatformMessage, 4, true},
      {"Window_respondToPlatformMessage", _RespondToPlatformMessage, 3, true},
      {"Window_render", Render, 2, true},
      {"Window_updateSemantics", UpdateSemantics, 2, true},
      {"Window_setIsolateDebugName", SetIsolateDebugName, 2, true},
      {"Window_reportUnhandledException", ReportUnhandledException, 2, true},
      {"Window_setNeedsReportTimings", SetNeedsReportTimings, 2, true},
      {"Window_getPersistentIsolateData", GetPersistentIsolateData, 1, true},
      {"Window_computePlatformResolvedLocale", _ComputePlatformResolvedLocale,
       2, true},
  });
}

2.到这里我们开始vsync的注册过程

  • 1.window.cc中方法
void ScheduleFrame(Dart_NativeArguments args) {
  UIDartState::ThrowIfUIOperationsProhibited();
  UIDartState::Current()->window()->client()->ScheduleFrame();
}
  • 2.runtime_controller.cc
void RuntimeController::ScheduleFrame() {
  client_.ScheduleFrame();
}

这里的client_ 是engin.cc :由runtim_control_创建过程可知道std::make_unique<RuntimeController>( *this...

    1. engin.cc
void Engine::ScheduleFrame(bool regenerate_layer_tree) {
  animator_->RequestFrame(regenerate_layer_tree);
}
  • 4.animator.cc
///头文件中 void ScheduleFrame(bool regenerate_layer_tree = true) override; 默认regenerate_layer_tree为true
///普通调用都是为true,特别的例子就是Shell::OnPlatformViewMarkTextureFrameAvailable()过程,设置参数为false,那么计划绘制一帧的时候就不需要重绘layer tree;
void Animator::RequestFrame(bool regenerate_layer_tree) {
  //是否复用上一次的图层的标记量,默认true
  if (regenerate_layer_tree) {
    regenerate_layer_tree_ = true;
  }
  
  if (paused_ && !dimension_change_pending_) {
    //暂停并且非挂起状态时也会被return
    return;
  }

  //获取信号量,失败之后直接return,成功往下执行,防止注册两个vsync,
  //flutter设计的原则当需要渲染则会调用到Engine的ScheduleFrame()来注册VSYNC信号回调,
  //一旦触发回调doFrame()执行完成后,便会移除回调方法,
  //也就是说一次注册一次回调,保证在一帧的时间窗口里UI线程只会生成一个layer tree发送给GPU线程
  if (!pending_frame_semaphore_.TryWait()) {
    return;
  }
  //将AwaitVSync post到UI线程执行
  task_runners_.GetUITaskRunner()->PostTask([self = weak_factory_.GetWeakPtr(),
                                             frame_number = frame_number_]() {
    if (!self.get()) {
      return;
    }
    TRACE_EVENT_ASYNC_BEGIN0("flutter", "Frame Request Pending", frame_number);
    self->AwaitVSync();
  });
  frame_scheduled_ = true;
}

以上pending_frame_semaphore_.TryWait会尝试获取信号量,获取成功会执行,否则失败,在UI Thread中执行完AwaitVSync方法之后会将信号量释放。(以下方法DrawLastLayerTreeBeginFrame中可见到)

    1. animator.cc
void Animator::AwaitVSync() {
  waiter_->AsyncWaitForVsync(
      [self = weak_factory_.GetWeakPtr()](fml::TimePoint frame_start_time,
                                          fml::TimePoint frame_target_time) {
        if (self) {
          //是否可以复用上一次的LayerTree(图层)
          if (self->CanReuseLastLayerTree()) {
            self->DrawLastLayerTree();
          } else {
            self->BeginFrame(frame_start_time, frame_target_time);
          }
        }
      });

  delegate_.OnAnimatorNotifyIdle(dart_frame_deadline_);
}
///是否可以复用上一次的LayerTree(图层树)
bool Animator::CanReuseLastLayerTree() {
  return !regenerate_layer_tree_;
}

regenerate_layer_tree_的值:
1.头文件中 void ScheduleFrame(bool regenerate_layer_tree = true) override; 默认regenerate_layer_tree为true
2.普通调用都是为true
3.特别的例子就是Shell::OnPlatformViewMarkTextureFrameAvailable()过程,设置参数为false,那么计划绘制一帧的时候就不需要重绘layer tree;

waiter_ 的对值:
waiter_对应VsyncWaiter(vsync_waiter.cc),由构造方法时传入的参数,它是有平台属性的,android中对应于VsyncWaiterAndroid,有也具有平台属性的 PlatformViewAndroid(platform_view_android.cc)#CreateVSyncWaiter创建。(PlatformViewAndroid继承自 PlatformView

  • 6.回调回来暂且不看,我们继续看VSYNC的注册过程AsyncWaitForVsync是调用在vsync_waiter.cc
void VsyncWaiter::AsyncWaitForVsync(const Callback& callback) {
  if (!callback) {
    return;
  }

  TRACE_EVENT0("flutter", "AsyncWaitForVsync");

  {
    std::scoped_lock lock(callback_mutex_);
    if (callback_) {
      //还是防止每一帧对应一个回调
      TRACE_EVENT_INSTANT0("flutter", "MultipleCallsToVsyncInFrameInterval");
      return;
    }
    //callback赋值
    callback_ = std::move(callback);
    if (secondary_callback_) {
      // Return directly as `AwaitVSync` is already called by
      // `ScheduleSecondaryCallback`.
      return;
    }
  }
  AwaitVSync();
}

1.6可知waiter_在android中是VsyncWaiterAndroid,所以AwaitVSync在android中执行的是VsyncWaiterAndroid下的AwaitVSync

  • 7.VsyncWaiterAndroid#AwaitVSync (vsync_waiter_android.cc)
// |VsyncWaiter|
void VsyncWaiterAndroid::AwaitVSync() {
  auto* weak_this = new std::weak_ptr<VsyncWaiter>(shared_from_this());
  jlong java_baton = reinterpret_cast<jlong>(weak_this);

  task_runners_.GetPlatformTaskRunner()->PostTask([java_baton]() {
    JNIEnv* env = fml::jni::AttachCurrentThread();
    env->CallStaticVoidMethod(g_vsync_waiter_class->obj(),     //
                              g_async_wait_for_vsync_method_,  //
                              java_baton                       //
    );
  });
}

其中g_async_wait_for_vsync_method_asyncWaitForVsync
g_vsync_waiter_class: env->FindClass("io/flutter/embedding/engine/FlutterJNI");
由此可见android中是进行了jni的调用,调用到了java层。
这两个值是在JNILoad的时候register的,会调用到VsyncWaiterAndroid::Register

  • 8.FlutterJNI#asyncWaitForVsync (FlutterJNI.java)
// Called by native.
  private static void asyncWaitForVsync(final long cookie) {
    if (asyncWaitForVsyncDelegate != null) {
      asyncWaitForVsyncDelegate.asyncWaitForVsync(cookie);
    } else {
      throw new IllegalStateException(
          "An AsyncWaitForVsyncDelegate must be registered with FlutterJNI before asyncWaitForVsync() is invoked.");
    }
  }
  • 9.VsyncWaiter.java
 private final FlutterJNI.AsyncWaitForVsyncDelegate asyncWaitForVsyncDelegate =
      new FlutterJNI.AsyncWaitForVsyncDelegate() {
        @Override
        public void asyncWaitForVsync(long cookie) {
        //此处进行VSYNC的注册
          Choreographer.getInstance()
              .postFrameCallback(
                  new Choreographer.FrameCallback() {
                    @Override
                    public void doFrame(long frameTimeNanos) {
                      float fps = windowManager.getDefaultDisplay().getRefreshRate();
                      long refreshPeriodNanos = (long) (1000000000.0 / fps);
                      FlutterJNI.nativeOnVsync(
                          frameTimeNanos, frameTimeNanos + refreshPeriodNanos, cookie);
                    }
                  });
        }
      };

到了此刻便是我们熟悉的android framwork层了,VSYNC被注册并等待VSYNC的信号回调doFrame执行callback。有关于Choreographer不做讲解,自行搜索文章。

初始化过程

上面1.7g_async_wait_for_vsync_method_的初始化是在JNILoad的时候进行初始化的,具体过程为:

  • 1.JNI_OnLoad (shell/platform/android/library_loader.cc)
// 首次加载共享库时此方法会被调用
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
  // 初始化java虚拟机
  fml::jni::InitJavaVM(vm);
  JNIEnv* env = fml::jni::AttachCurrentThread();
  bool result = false;
  // 注册FlutterMain
  result = flutter::FlutterMain::Register(env);
  FML_CHECK(result);
  //注册PlatformViewAndroid
  result = flutter::PlatformViewAndroid::Register(env);
  FML_CHECK(result);
  //注册VsyncWaiterAndroid
  result = flutter::VsyncWaiterAndroid::Register(env);
  FML_CHECK(result);
  return JNI_VERSION_1_4;
}
    1. flutter_main.cc: 注册FlutterJNI的nativePrefetchDefaultFontManager以及nativeInit
bool FlutterMain::Register(JNIEnv* env) {
  static const JNINativeMethod methods[] = {
      {
          .name = "nativeInit",
          .signature = "(Landroid/content/Context;[Ljava/lang/String;Ljava/"
                       "lang/String;Ljava/lang/String;Ljava/lang/String;J)V",
          .fnPtr = reinterpret_cast<void*>(&Init),
      },
      {
          .name = "nativePrefetchDefaultFontManager",
          .signature = "()V",
          .fnPtr = reinterpret_cast<void*>(&PrefetchDefaultFontManager),
      },
  };

  jclass clazz = env->FindClass("io/flutter/embedding/engine/FlutterJNI");

  if (clazz == nullptr) {
    return false;
  }

  return env->RegisterNatives(clazz, methods, fml::size(methods)) == 0;
}

  • 3.platform_view_android_jni_impl.cc #Register:此方法主要注册了FlutterJNI,FlutterCallbackInformation,android/graphics/SurfaceTexture等的类
bool RegisterApi(JNIEnv* env) {
  static const JNINativeMethod flutter_jni_methods[] = {
      // Start of methods from FlutterJNI
      {
          .name = "nativeAttach",
          .signature = "(Lio/flutter/embedding/engine/FlutterJNI;Z)J",
          .fnPtr = reinterpret_cast<void*>(&AttachJNI),
      },
      {
          .name = "nativeDestroy",
          .signature = "(J)V",
          .fnPtr = reinterpret_cast<void*>(&DestroyJNI),
      },
      {
          .name = "nativeRunBundleAndSnapshotFromLibrary",
          .signature = "(JLjava/lang/String;Ljava/lang/String;"
                       "Ljava/lang/String;Landroid/content/res/AssetManager;)V",
          .fnPtr = reinterpret_cast<void*>(&RunBundleAndSnapshotFromLibrary),
      },
      {
          .name = "nativeDispatchEmptyPlatformMessage",
          .signature = "(JLjava/lang/String;I)V",
          .fnPtr = reinterpret_cast<void*>(&DispatchEmptyPlatformMessage),
      },
      {
          .name = "nativeDispatchPlatformMessage",
          .signature = "(JLjava/lang/String;Ljava/nio/ByteBuffer;II)V",
          .fnPtr = reinterpret_cast<void*>(&DispatchPlatformMessage),
      },
      {
          .name = "nativeInvokePlatformMessageResponseCallback",
          .signature = "(JILjava/nio/ByteBuffer;I)V",
          .fnPtr =
              reinterpret_cast<void*>(&InvokePlatformMessageResponseCallback),
      },
      {
          .name = "nativeInvokePlatformMessageEmptyResponseCallback",
          .signature = "(JI)V",
          .fnPtr = reinterpret_cast<void*>(
              &InvokePlatformMessageEmptyResponseCallback),
      },
      {
          .name = "nativeNotifyLowMemoryWarning",
          .signature = "(J)V",
          .fnPtr = reinterpret_cast<void*>(&NotifyLowMemoryWarning),
      },

      // Start of methods from FlutterView
      {
          .name = "nativeGetBitmap",
          .signature = "(J)Landroid/graphics/Bitmap;",
          .fnPtr = reinterpret_cast<void*>(&GetBitmap),
      },
      {
          .name = "nativeSurfaceCreated",
          .signature = "(JLandroid/view/Surface;)V",
          .fnPtr = reinterpret_cast<void*>(&SurfaceCreated),
      },
      {
          .name = "nativeSurfaceWindowChanged",
          .signature = "(JLandroid/view/Surface;)V",
          .fnPtr = reinterpret_cast<void*>(&SurfaceWindowChanged),
      },
      {
          .name = "nativeSurfaceChanged",
          .signature = "(JII)V",
          .fnPtr = reinterpret_cast<void*>(&SurfaceChanged),
      },
      {
          .name = "nativeSurfaceDestroyed",
          .signature = "(J)V",
          .fnPtr = reinterpret_cast<void*>(&SurfaceDestroyed),
      },
      {
          .name = "nativeSetViewportMetrics",
          .signature = "(JFIIIIIIIIIIIIII)V",
          .fnPtr = reinterpret_cast<void*>(&SetViewportMetrics),
      },
      {
          .name = "nativeDispatchPointerDataPacket",
          .signature = "(JLjava/nio/ByteBuffer;I)V",
          .fnPtr = reinterpret_cast<void*>(&DispatchPointerDataPacket),
      },
      {
          .name = "nativeDispatchSemanticsAction",
          .signature = "(JIILjava/nio/ByteBuffer;I)V",
          .fnPtr = reinterpret_cast<void*>(&DispatchSemanticsAction),
      },
      {
          .name = "nativeSetSemanticsEnabled",
          .signature = "(JZ)V",
          .fnPtr = reinterpret_cast<void*>(&SetSemanticsEnabled),
      },
      {
          .name = "nativeSetAccessibilityFeatures",
          .signature = "(JI)V",
          .fnPtr = reinterpret_cast<void*>(&SetAccessibilityFeatures),
      },
      {
          .name = "nativeGetIsSoftwareRenderingEnabled",
          .signature = "()Z",
          .fnPtr = reinterpret_cast<void*>(&GetIsSoftwareRendering),
      },
      {
          .name = "nativeRegisterTexture",
          .signature = "(JJLandroid/graphics/SurfaceTexture;)V",
          .fnPtr = reinterpret_cast<void*>(&RegisterTexture),
      },
      {
          .name = "nativeMarkTextureFrameAvailable",
          .signature = "(JJ)V",
          .fnPtr = reinterpret_cast<void*>(&MarkTextureFrameAvailable),
      },
      {
          .name = "nativeUnregisterTexture",
          .signature = "(JJ)V",
          .fnPtr = reinterpret_cast<void*>(&UnregisterTexture),
      },

      // Methods for Dart callback functionality.
      {
          .name = "nativeLookupCallbackInformation",
          .signature = "(J)Lio/flutter/view/FlutterCallbackInformation;",
          .fnPtr = reinterpret_cast<void*>(&LookupCallbackInformation),
      },

      // Start of methods for FlutterTextUtils
      {
          .name = "nativeFlutterTextUtilsIsEmoji",
          .signature = "(I)Z",
          .fnPtr = reinterpret_cast<void*>(&FlutterTextUtilsIsEmoji),
      },
      {
          .name = "nativeFlutterTextUtilsIsEmojiModifier",
          .signature = "(I)Z",
          .fnPtr = reinterpret_cast<void*>(&FlutterTextUtilsIsEmojiModifier),
      },
      {
          .name = "nativeFlutterTextUtilsIsEmojiModifierBase",
          .signature = "(I)Z",
          .fnPtr =
              reinterpret_cast<void*>(&FlutterTextUtilsIsEmojiModifierBase),
      },
      {
          .name = "nativeFlutterTextUtilsIsVariationSelector",
          .signature = "(I)Z",
          .fnPtr =
              reinterpret_cast<void*>(&FlutterTextUtilsIsVariationSelector),
      },
      {
          .name = "nativeFlutterTextUtilsIsRegionalIndicator",
          .signature = "(I)Z",
          .fnPtr =
              reinterpret_cast<void*>(&FlutterTextUtilsIsRegionalIndicator),
      },
  };

  if (env->RegisterNatives(g_flutter_jni_class->obj(), flutter_jni_methods,
                           fml::size(flutter_jni_methods)) != 0) {
    FML_LOG(ERROR) << "Failed to RegisterNatives with FlutterJNI";
    return false;
  }

  g_handle_platform_message_method =
      env->GetMethodID(g_flutter_jni_class->obj(), "handlePlatformMessage",
                       "(Ljava/lang/String;[BI)V");

  if (g_handle_platform_message_method == nullptr) {
    FML_LOG(ERROR) << "Could not locate handlePlatformMessage method";
    return false;
  }

  g_handle_platform_message_response_method = env->GetMethodID(
      g_flutter_jni_class->obj(), "handlePlatformMessageResponse", "(I[B)V");

  if (g_handle_platform_message_response_method == nullptr) {
    FML_LOG(ERROR) << "Could not locate handlePlatformMessageResponse method";
    return false;
  }

  g_update_semantics_method =
      env->GetMethodID(g_flutter_jni_class->obj(), "updateSemantics",
                       "(Ljava/nio/ByteBuffer;[Ljava/lang/String;)V");

  if (g_update_semantics_method == nullptr) {
    FML_LOG(ERROR) << "Could not locate updateSemantics method";
    return false;
  }

  g_update_custom_accessibility_actions_method = env->GetMethodID(
      g_flutter_jni_class->obj(), "updateCustomAccessibilityActions",
      "(Ljava/nio/ByteBuffer;[Ljava/lang/String;)V");

  if (g_update_custom_accessibility_actions_method == nullptr) {
    FML_LOG(ERROR)
        << "Could not locate updateCustomAccessibilityActions method";
    return false;
  }

  g_on_first_frame_method =
      env->GetMethodID(g_flutter_jni_class->obj(), "onFirstFrame", "()V");

  if (g_on_first_frame_method == nullptr) {
    FML_LOG(ERROR) << "Could not locate onFirstFrame method";
    return false;
  }

  g_on_engine_restart_method =
      env->GetMethodID(g_flutter_jni_class->obj(), "onPreEngineRestart", "()V");

  if (g_on_engine_restart_method == nullptr) {
    FML_LOG(ERROR) << "Could not locate onEngineRestart method";
    return false;
  }

  g_create_overlay_surface_method =
      env->GetMethodID(g_flutter_jni_class->obj(), "createOverlaySurface",
                       "()Lio/flutter/embedding/engine/FlutterOverlaySurface;");

  if (g_create_overlay_surface_method == nullptr) {
    FML_LOG(ERROR) << "Could not locate createOverlaySurface method";
    return false;
  }

  g_destroy_overlay_surfaces_method = env->GetMethodID(
      g_flutter_jni_class->obj(), "destroyOverlaySurfaces", "()V");

  if (g_destroy_overlay_surfaces_method == nullptr) {
    FML_LOG(ERROR) << "Could not locate destroyOverlaySurfaces method";
    return false;
  }

  fml::jni::ScopedJavaLocalRef<jclass> overlay_surface_class(
      env, env->FindClass("io/flutter/embedding/engine/FlutterOverlaySurface"));
  if (overlay_surface_class.is_null()) {
    FML_LOG(ERROR) << "Could not locate FlutterOverlaySurface class";
    return false;
  }
  g_overlay_surface_id_method =
      env->GetMethodID(overlay_surface_class.obj(), "getId", "()I");
  if (g_overlay_surface_id_method == nullptr) {
    FML_LOG(ERROR) << "Could not locate FlutterOverlaySurface#getId() method";
    return false;
  }
  g_overlay_surface_surface_method = env->GetMethodID(
      overlay_surface_class.obj(), "getSurface", "()Landroid/view/Surface;");
  if (g_overlay_surface_surface_method == nullptr) {
    FML_LOG(ERROR)
        << "Could not locate FlutterOverlaySurface#getSurface() method";
    return false;
  }

  return true;
}

bool PlatformViewAndroid::Register(JNIEnv* env) {
  if (env == nullptr) {
    FML_LOG(ERROR) << "No JNIEnv provided";
    return false;
  }

  g_flutter_callback_info_class = new fml::jni::ScopedJavaGlobalRef<jclass>(
      env, env->FindClass("io/flutter/view/FlutterCallbackInformation"));
  if (g_flutter_callback_info_class->is_null()) {
    FML_LOG(ERROR) << "Could not locate FlutterCallbackInformation class";
    return false;
  }

  g_flutter_callback_info_constructor = env->GetMethodID(
      g_flutter_callback_info_class->obj(), "<init>",
      "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
  if (g_flutter_callback_info_constructor == nullptr) {
    FML_LOG(ERROR) << "Could not locate FlutterCallbackInformation constructor";
    return false;
  }

  g_flutter_jni_class = new fml::jni::ScopedJavaGlobalRef<jclass>(
      env, env->FindClass("io/flutter/embedding/engine/FlutterJNI"));
  if (g_flutter_jni_class->is_null()) {
    FML_LOG(ERROR) << "Failed to find FlutterJNI Class.";
    return false;
  }

  g_mutators_stack_class = new fml::jni::ScopedJavaGlobalRef<jclass>(
      env,
      env->FindClass(
          "io/flutter/embedding/engine/mutatorsstack/FlutterMutatorsStack"));
  if (g_mutators_stack_class == nullptr) {
    FML_LOG(ERROR) << "Could not locate FlutterMutatorsStack";
    return false;
  }

  g_mutators_stack_init_method =
      env->GetMethodID(g_mutators_stack_class->obj(), "<init>", "()V");
  if (g_mutators_stack_init_method == nullptr) {
    FML_LOG(ERROR) << "Could not locate FlutterMutatorsStack.init method";
    return false;
  }

  g_mutators_stack_push_transform_method =
      env->GetMethodID(g_mutators_stack_class->obj(), "pushTransform", "([F)V");
  if (g_mutators_stack_push_transform_method == nullptr) {
    FML_LOG(ERROR)
        << "Could not locate FlutterMutatorsStack.pushTransform method";
    return false;
  }

  g_mutators_stack_push_cliprect_method = env->GetMethodID(
      g_mutators_stack_class->obj(), "pushClipRect", "(IIII)V");
  if (g_mutators_stack_push_cliprect_method == nullptr) {
    FML_LOG(ERROR)
        << "Could not locate FlutterMutatorsStack.pushCilpRect method";
    return false;
  }

  g_on_display_platform_view_method =
      env->GetMethodID(g_flutter_jni_class->obj(), "onDisplayPlatformView",
                       "(IIIIIIILio/flutter/embedding/engine/mutatorsstack/"
                       "FlutterMutatorsStack;)V");

  if (g_on_display_platform_view_method == nullptr) {
    FML_LOG(ERROR) << "Could not locate onDisplayPlatformView method";
    return false;
  }

  g_on_begin_frame_method =
      env->GetMethodID(g_flutter_jni_class->obj(), "onBeginFrame", "()V");

  if (g_on_begin_frame_method == nullptr) {
    FML_LOG(ERROR) << "Could not locate onBeginFrame method";
    return false;
  }

  g_on_end_frame_method =
      env->GetMethodID(g_flutter_jni_class->obj(), "onEndFrame", "()V");

  if (g_on_end_frame_method == nullptr) {
    FML_LOG(ERROR) << "Could not locate onEndFrame method";
    return false;
  }

  g_on_display_overlay_surface_method = env->GetMethodID(
      g_flutter_jni_class->obj(), "onDisplayOverlaySurface", "(IIIII)V");

  if (g_on_display_overlay_surface_method == nullptr) {
    FML_LOG(ERROR) << "Could not locate onDisplayOverlaySurface method";
    return false;
  }

  g_surface_texture_class = new fml::jni::ScopedJavaGlobalRef<jclass>(
      env, env->FindClass("android/graphics/SurfaceTexture"));
  if (g_surface_texture_class->is_null()) {
    FML_LOG(ERROR) << "Could not locate SurfaceTexture class";
    return false;
  }

  g_attach_to_gl_context_method = env->GetMethodID(
      g_surface_texture_class->obj(), "attachToGLContext", "(I)V");

  if (g_attach_to_gl_context_method == nullptr) {
    FML_LOG(ERROR) << "Could not locate attachToGlContext method";
    return false;
  }

  g_update_tex_image_method =
      env->GetMethodID(g_surface_texture_class->obj(), "updateTexImage", "()V");

  if (g_update_tex_image_method == nullptr) {
    FML_LOG(ERROR) << "Could not locate updateTexImage method";
    return false;
  }

  g_get_transform_matrix_method = env->GetMethodID(
      g_surface_texture_class->obj(), "getTransformMatrix", "([F)V");

  if (g_get_transform_matrix_method == nullptr) {
    FML_LOG(ERROR) << "Could not locate getTransformMatrix method";
    return false;
  }

  g_detach_from_gl_context_method = env->GetMethodID(
      g_surface_texture_class->obj(), "detachFromGLContext", "()V");

  if (g_detach_from_gl_context_method == nullptr) {
    FML_LOG(ERROR) << "Could not locate detachFromGlContext method";
    return false;
  }

  g_compute_platform_resolved_locale_method = env->GetMethodID(
      g_flutter_jni_class->obj(), "computePlatformResolvedLocale",
      "([Ljava/lang/String;)[Ljava/lang/String;");

  if (g_compute_platform_resolved_locale_method == nullptr) {
    FML_LOG(ERROR) << "Could not locate computePlatformResolvedLocale method";
    return false;
  }

  return RegisterApi(env);
}
  • 4.VsyncWaiterAndroid#Register(vsync_waiter_android.cc)
// static
bool VsyncWaiterAndroid::Register(JNIEnv* env) {
  static const JNINativeMethod methods[] = {{
      .name = "nativeOnVsync",
      .signature = "(JJJ)V",
      .fnPtr = reinterpret_cast<void*>(&OnNativeVsync),
  }};

  jclass clazz = env->FindClass("io/flutter/embedding/engine/FlutterJNI");

  if (clazz == nullptr) {
    return false;
  }

  g_vsync_waiter_class = new fml::jni::ScopedJavaGlobalRef<jclass>(env, clazz);

  FML_CHECK(!g_vsync_waiter_class->is_null());

  g_async_wait_for_vsync_method_ = env->GetStaticMethodID(
      g_vsync_waiter_class->obj(), "asyncWaitForVsync", "(J)V");

  FML_CHECK(g_async_wait_for_vsync_method_ != nullptr);

  return env->RegisterNatives(clazz, methods, fml::size(methods)) == 0;
}

1.1.7中的方法调用,其中的g_async_wait_for_vsync_method_ g_vsync_waiter_class等字段此时被赋值
2.将FlutterJNI中的nativeOnVsync跟VsyncWaiterAndroid#OnNativeVsync进行绑定。

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