Libflutter. So can be used to load libflutter. In FlutterEngin and FlutterActivityDelegate initializations for android and FlutterActivityDelegate UI initializations Platform_view_android_jni. cc calls AttachJNI initialization AndroidShellHolder object to initialize the platform and analyze the initialization process of FlutterEngine.

!!!!!!!!! Info “Flutter Engine initialization process”

* 1. 'Platfrom,UI,IO,GUP' thread management, load configuration parameters * 2. 3. 'thread_host_' manages the associated threads and hosts four runners along 'TaskRunner', 'TaskRunners' * 4.' PlatformViewAndroid 'is created, Responsible for managing the platform side is event handling performed on the UI thread * 5. 'Rasterizer' initialization rasterization performed on the GPU thread * 6. 'MessageLoop' creation, running on platfrom * 7. Responsible for managing the four tasks of the runner * 8. 'Shell' loading third-party libraries, Java virtual machine creationCopy the code

Load Flutter resources

JNI_OnLoad

Flutter. So the Android side entrance function engine/SRC/Flutter/shell/platform/Android/library_loader. Cc

When Java loads the Flutter. So library, it starts to initialize the Flutter engine

1. Register the code for the Flutter layer

2. Initialize AndroidView

3. Initialize FlutterMain

Initializing the environment associated with Flutter on Android is done in two steps:

// This is called by the VM when the shared library is first loaded.
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
  // Initialize the Java VM.
  fml::jni::InitJavaVM(vm);

  JNIEnv* env = fml::jni::AttachCurrentThread();
  bool result = false;

  // Register FlutterMain.
  result = shell::FlutterMain::Register(env);
  FML_CHECK(result);

  // Register PlatformView
  result = shell::PlatformViewAndroid::Register(env);
  FML_CHECK(result);

  // Register VSyncWaiter.
  result = shell::VsyncWaiterAndroid::Register(env);
  FML_CHECK(result);

  return JNI_VERSION_1_4;
}

Copy the code

FlutterMain::Register(env);

1. Convert the nativeInit function in FlutterJNI to the JNIinit function and initialize the related engine

2. Load all native functions in FlutterMain

Start initializing Register to find Java methods in Flutter. Jar

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;) V",
          .fnPtr = reinterpret_cast<void*>(&Init),
      },
      {
          .name = "nativeRecordStartTimestamp",
          .signature = "(J)V",
          .fnPtr = reinterpret_cast<void*>(&RecordStartTimestamp),
      },
  };

  jclass clazz = env->FindClass("io/flutter/view/FlutterMain");

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

  return env->RegisterNatives(clazz, methods, arraysize(methods)) == 0;
}
Copy the code

Fluttermain. cc file is the entry class related to FlutterEngine and Android platform. It mainly deals with Android-related resource files and initializes Fluttermain. cc

1. When the Register function is called, nativeInit in FlutterJNI has been mapped to nativeInit in FlutterMain, and relevant files of Flutter on Android are passed in

2. Find the resource files extracted from the Apk package when the Android engine starts

3. Load the related file kernel_blob compiled by Flutter

4. Initialize fluttermaing_flutter_main. reset(new FlutterMain(STD ::move(Settings)));

void FlutterMain::Init(JNIEnv* env,
                       jclass clazz,
                       jobject context,
                       jobjectArray jargs,
                       jstring bundlePath,
                       jstring appStoragePath,
                       jstring engineCachesPath) {
  std: :vector<std: :string> args;
  args.push_back("flutter");
  for (auto& arg : fml::jni::StringArrayToVector(env, jargs)) {
    args.push_back(std::move(arg));
  }
  auto command_line = fml::CommandLineFromIterators(args.begin(), args.end());

  auto settings = SettingsFromCommandLine(command_line);

  settings.assets_path = fml::jni::JavaStringToString(env, bundlePath);

  // Restore the callback cache.
  // TODO(chinmaygarde): Route all cache file access through FML and remove this
  // setter.
  blink::DartCallbackCache::SetCachePath(
      fml::jni::JavaStringToString(env, appStoragePath));

  fml::paths::InitializeAndroidCachesPath(
      fml::jni::JavaStringToString(env, engineCachesPath));

  blink::DartCallbackCache::LoadCacheFromDisk();

  if(! blink::DartVM::IsRunningPrecompiledCode()) {// Check to see if the appropriate kernel files are present and configure
    // settings accordingly.
    auto application_kernel_path =
        fml::paths::JoinPaths({settings.assets_path, "kernel_blob.bin"});

    if (fml::IsFile(application_kernel_path)) {
      settings.application_kernel_asset = application_kernel_path;
    }
  }

  settings.task_observer_add = [](intptr_t key, fml::closure callback) {
    fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback));
  };

  settings.task_observer_remove = [](intptr_t key) {
    fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
  };

#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
  // There are no ownership concerns here as all mappings are owned by the
  // embedder and not the engine.
  auto make_mapping_callback = [](const uint8_t* mapping, size_t size) {
    return [mapping, size]() {
      return std::make_unique<fml::NonOwnedMapping>(mapping, size);
    };
  };

  settings.dart_library_sources_kernel =
      make_mapping_callback(kPlatformStrongDill, kPlatformStrongDillSize);
#endif  // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG

  // Not thread safe. Will be removed when FlutterMain is refactored to no
  // longer be a singleton.
  g_flutter_main.reset(new FlutterMain(std::move(settings)));
}
Copy the code

Now that the Flutter resource files have been loaded, you need to initialize the View logic to communicate with Android

In the figure below:

  • 1. Initialize the environment in which the Flutter Engine runs the FlutterUI library. Initialize AndroidShellHolder to manage the surrounding Flutter environment
  • 2.PlatformViewAndroid performs View drawing and event processing in the JNI layer, registers SurfaceView to Flutter Eingine, provides the engine with the canvas to draw on. Call the ANative_window class to bridge FlutterUI and AndroidUI

PlatformViewAndroid

Binding relationships for JNI calls

Initialize the View logic of the Android platform, bind the Flutter. Jar class and the initial binding of the Android drawing engine. The main contents of the initialization work are to register the local methods of the relevant Java layer to the JNI layer, and establish a good relationship between C++ and Java layer calling function

1.io/flutter/view/FlutterCallbackInformation

2.io/flutter/embedding/engine/FlutterJNI

3.android/graphics/SurfaceTexture

4.attachToGLContext

5.updateTexImage

6.getTransformMatrix

7.detachFromGLContext

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_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;
  }

  static const JNINativeMethod callback_info_methods[] = {
      {
          .name = "nativeLookupCallbackInformation",
          .signature = "(J)Lio/flutter/view/FlutterCallbackInformation;",
          .fnPtr = reinterpret_cast<void*>(&shell::LookupCallbackInformation),
      },
  };

  if(env->RegisterNatives(g_flutter_callback_info_class->obj(), callback_info_methods, arraysize(callback_info_methods)) ! =0) {
    FML_LOG(ERROR) << "Failed to RegisterNatives with FlutterCallbackInfo";
    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;
  }

  returnRegisterApi(env); }}// namespace shell

Copy the code

Initializes FlutterView’s own environment by registering the Android logic associated with View operations

FlutterJNI

  1.AttachJNI
  2.DestroyJNI
  3.AssetManager
Copy the code
bool RegisterApi(JNIEnv* env) {
  static const JNINativeMethod flutter_jni_methods[] = {
      // Start of methods from FlutterNativeView
      {
          .name = "nativeAttach",
          .signature = "(Lio/flutter/embedding/engine/FlutterJNI; Z)J",
          .fnPtr = reinterpret_cast<void*>(&shell::AttachJNI),
      },
      {
          .name = "nativeDestroy",
          .signature = "(J)V",
          .fnPtr = reinterpret_cast<void*>(&shell::DestroyJNI),
      },
      {
          .name = "nativeRunBundleAndSnapshotFromLibrary",
          .signature = "(J[Ljava/lang/String;Ljava/lang/String;"
                       "Ljava/lang/String; Landroid/content/res/AssetManager;) V",
          .fnPtr =
              reinterpret_cast<void*>(&shell::RunBundleAndSnapshotFromLibrary),
      },
      {
          .name = "nativeGetObservatoryUri",
          .signature = "()Ljava/lang/String;",
          .fnPtr = reinterpret_cast<void*>(&shell::GetObservatoryUri),
      },
      {
          .name = "nativeDispatchEmptyPlatformMessage",
          .signature = "(JLjava/lang/String; I)V",
          .fnPtr =
              reinterpret_cast<void*>(&shell::DispatchEmptyPlatformMessage),
      },
      {
          .name = "nativeDispatchPlatformMessage",
          .signature = "(JLjava/lang/String; Ljava/nio/ByteBuffer; II)V",
          .fnPtr = reinterpret_cast<void*>(&shell::DispatchPlatformMessage),
      },
      {
          .name = "nativeInvokePlatformMessageResponseCallback",
          .signature = "(JILjava/nio/ByteBuffer; I)V",
          .fnPtr = reinterpret_cast<void*>(
              &shell::InvokePlatformMessageResponseCallback),
      },
      {
          .name = "nativeInvokePlatformMessageEmptyResponseCallback",
          .signature = "(JI)V",
          .fnPtr = reinterpret_cast<void*>(
              &shell::InvokePlatformMessageEmptyResponseCallback),
      },

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

  if(env->RegisterNatives(g_flutter_jni_class->obj(), flutter_jni_methods, arraysize(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;
  }

  return true;
}
Copy the code

FlutterView initialization

The FlutterNativeView initializes and registers the Android PluginMessage into the JNI

public FlutterNativeView(@NonNull Context context, boolean isBackgroundView) {
        this.flutterUiDisplayListener = new FlutterUiDisplayListener() {
            public void onFlutterUiDisplayed(a) {
                if (FlutterNativeView.this.mFlutterView ! =null) {
                    FlutterNativeView.this.mFlutterView.onFirstFrame(); }}public void onFlutterUiNoLongerDisplayed(a) {}};this.mContext = context;
        this.mPluginRegistry = new FlutterPluginRegistry(this, context);
        this.mFlutterJNI = new FlutterJNI();
        this.mFlutterJNI.addIsDisplayingFlutterUiListener(this.flutterUiDisplayListener);
        this.dartExecutor = new DartExecutor(this.mFlutterJNI, context.getAssets());
        this.mFlutterJNI.addEngineLifecycleListener(new FlutterNativeView.EngineLifecycleListenerImpl());
        this.attach(this, isBackgroundView);
        this.assertAttached();
    }
Copy the code

FlutterNativeView

public FlutterNativeView(@NonNull Context context, boolean isBackgroundView) {
    this.flutterUiDisplayListener = new FlutterUiDisplayListener() {
        public void onFlutterUiDisplayed(a) {
            if (FlutterNativeView.this.mFlutterView ! =null) {
                FlutterNativeView.this.mFlutterView.onFirstFrame(); }}public void onFlutterUiNoLongerDisplayed(a) {}};this.mContext = context;
    this.mPluginRegistry = new FlutterPluginRegistry(this, context);
    this.mFlutterJNI = new FlutterJNI();
    this.mFlutterJNI.addIsDisplayingFlutterUiListener(this.flutterUiDisplayListener);
    this.dartExecutor = new DartExecutor(this.mFlutterJNI, context.getAssets());
    this.mFlutterJNI.addEngineLifecycleListener(newFlutterNativeView.EngineLifecycleListenerImpl()); Initialize the JINthis.attach(this, isBackgroundView);
    this.assertAttached();
}
Copy the code

AttachJNI

The next layer is analyzed in the JNI invocation process: AttachJNI invokes the STD: : make_unique < AndroidShellHolder > create AndroidShellHolder instance engine/SRC/flutter/shell/platf orm/android/platform_view_android_jni.cc

    // Called By Java
    // the method registers into JNI
    static jlong AttachJNI(JNIEnv* env, jclass clazz, jobject flutterJNI, jboolean is_background_view) {
      fml::jni::JavaObjectWeakGlobalRef java_object(env, flutterJNI);
      auto shell_holder = std::make_unique<AndroidShellHolder>(
          FlutterMain::Get().GetSettings(), java_object, is_background_view);
      if (shell_holder->IsValid()) {
        return reinterpret_cast<jlong>(shell_holder.release());
      } else {
        return 0; }}Copy the code

AndroidShellHolder class is the Platfrom layer to call JNI interface as a proxy object for unified proxy entry, using C++11 smart pointer object to unified management of an object C++ smart pointer

AndroidShellHolder

Initialization entry for FlutterEngine

AndroidShellHolder: a portal that manages the Flutter engine on the Platform side:

  • 1. Management of Platfrom,UI,IO and GUP threads and loading of configuration parameters
  • 2. Create a thread to clear the vm exit
  • 3. Thread_host_ manages related threads and hosts four of them
  • 4. The Creation of PlatformViewAndroid, which is responsible for managing the platform side is the execution of event processing in the UI thread
  • 5.Rasterizer’s initial rasterization is performed on the GPU thread
  • 6. Create MessageLoop, run in platfrom
  • 7.TaskRunners manage thread execution that is added to different platforms and is responsible for managing the four TaskRunners
  • 8.Shell loading third-party library, Java VIRTUAL machine creation

// Parameter description:
//
// blink::Settings Settings,// Configure data
/ / FML: : jni: : JavaObjectWeakGlobalRef java_object, / / FlutterJNI object
// bool is_background_view
// static size_t shell_count = 1; Shell: The number of objects is one
/ / finish:
// 1. Load the Settings configuration file and bind the global javA_Object
// 2. Create a thread to clean up the vm exit
The ThreadHost class manages the Platform, IO, GPU, and UI threads of the Flutter engine
/ / 4. Initialize the message queue: FML: : MessageLoop: : EnsureInitializedForCurrentThread ();
    // Initialization entry for FlutterEngine
AndroidShellHolder::AndroidShellHolder(
    blink::Settings settings,
    fml::jni::JavaObjectWeakGlobalRef java_object,
    bool is_background_view)
    : settings_(std::move(settings)), java_object_(java_object) {
  static size_t shell_count = 1;
  auto thread_label = std::to_string(shell_count++);
  // Create a thread to clean up the virtual machine exit cleanup
  FML_CHECK(pthread_key_create(&thread_destruct_key_, ThreadDestructCallback) ==
            0);

  if (is_background_view) {
    thread_host_ = {thread_label, ThreadHost::Type::UI};
  } else {
    thread_host_ = {thread_label, ThreadHost::Type::UI | ThreadHost::Type::GPU |
                                      ThreadHost::Type::IO};
  }

  // Detach from JNI when the UI and GPU threads exit.
  auto jni_exit_task([key = thread_destruct_key_]() {
    FML_CHECK(pthread_setspecific(key, reinterpret_cast<void* > (1)) = =0);
  });
  thread_host_.ui_thread->GetTaskRunner()->PostTask(jni_exit_task);
  if(! is_background_view) { thread_host_.gpu_thread->GetTaskRunner()->PostTask(jni_exit_task); } fml::WeakPtr<PlatformViewAndroid> weak_platform_view; Shell::CreateCallback<PlatformView> on_create_platform_view = [is_background_view, java_object, &weak_platform_view](Shell& shell) {std: :unique_ptr<PlatformViewAndroid> platform_view_android;
        if (is_background_view) {
          platform_view_android = std::make_unique<PlatformViewAndroid>(
              shell,                   // delegate
              shell.GetTaskRunners(),  // task runners
              java_object              // java object handle for JNI interop
          );

        } else {
          platform_view_android = std::make_unique<PlatformViewAndroid>(
              shell,                   // delegate
              shell.GetTaskRunners(),  // task runners
              java_object,             // java object handle for JNI interop
              shell.GetSettings()
                  .enable_software_rendering  // use software rendering
          );
        }
        weak_platform_view = platform_view_android->GetWeakPtr();
        return platform_view_android;
      };

  Shell::CreateCallback<Rasterizer> on_create_rasterizer = [](Shell& shell) {
    return std::make_unique<Rasterizer>(shell.GetTaskRunners());
  };

  // The current thread will be used as the platform thread. Ensure that the
  // message loop is initialized.
  fml::MessageLoop::EnsureInitializedForCurrentThread();
  fml::RefPtr<fml::TaskRunner> gpu_runner;
  fml::RefPtr<fml::TaskRunner> ui_runner;
  fml::RefPtr<fml::TaskRunner> io_runner;
  fml::RefPtr<fml::TaskRunner> platform_runner =
      fml::MessageLoop::GetCurrent().GetTaskRunner();
  if (is_background_view) {
    auto single_task_runner = thread_host_.ui_thread->GetTaskRunner();
    gpu_runner = single_task_runner;
    ui_runner = single_task_runner;
    io_runner = single_task_runner;
  } else {
    gpu_runner = thread_host_.gpu_thread->GetTaskRunner();
    ui_runner = thread_host_.ui_thread->GetTaskRunner();
    io_runner = thread_host_.io_thread->GetTaskRunner();
  }
  blink::TaskRunners task_runners(thread_label,     // label
                                  platform_runner,  // platform
                                  gpu_runner,       // gpu
                                  ui_runner,        // ui
                                  io_runner         // io
  );

  shell_ =
      Shell::Create(task_runners,             // task runners
                    settings_,                // settings
                    on_create_platform_view,  // platform view create callback
                    on_create_rasterizer      // rasterizer create callback); platform_view_ = weak_platform_view; FML_DCHECK(platform_view_); is_valid_ = shell_ ! =nullptr;

  if (is_valid_) {
    task_runners.GetGPUTaskRunner()->PostTask([]() {
      // Android describes -8 as "most important display threads, for
      // compositing the screen and retrieving input events". Conservatively
      // set the GPU thread to slightly lower priority than it.
      if (::setpriority(PRIO_PROCESS, gettid(), - 5) != 0) {
        // Defensive fallback. Depending on the OEM, it may not be possible
        // to set priority to -5.
        if (::setpriority(PRIO_PROCESS, gettid(), 2 -) != 0) {
          FML_LOG(ERROR) << "Failed to set GPU task runner priority"; }}}); task_runners.GetUITaskRunner()->PostTask([]() {if (::setpriority(PRIO_PROCESS, gettid(), - 1) != 0) {
        FML_LOG(ERROR) << "Failed to set UI task runner priority"; }}); }}Copy the code

Create a thread to handle the JNI exit task

Create a thread to clean up after the DartVM exits and add it to ui_thread, if is_background_view(which is passed in the FlutterJNI call) is working in the background, add it to GPU_Thread as well

// Create a thread to clean up the virtual machine exit cleanup
FML_CHECK(pthread_key_create(&thread_destruct_key_, ThreadDestructCallback) == 0);
Copy the code
// Detach from JNI when the UI and GPU threads exit.
auto jni_exit_task([key = thread_destruct_key_]() {
  FML_CHECK(pthread_setspecific(key, reinterpret_cast<void* > (1)) = =0);
});
thread_host_.ui_thread->GetTaskRunner()->PostTask(jni_exit_task);
if(! is_background_view) { thread_host_.gpu_thread->GetTaskRunner()->PostTask(jni_exit_task); }Copy the code

Flutter Engine thread pool mode

The Flutter Engine requires the Embeder to provide four Task Runners, which refers to the middle-tier code that ports the Engine to the platform. The four main Task runners include:

flutterThread.jpeg

Determine the type of thread to be created based on the arguments passed in the Java layer to call the Native layer:

  • 1. Create a ThreadHost to manage four thread objects
  • Define a proxy class for a thread class/engine/src/flutter/fml/thread.cc
  • 3. Create MessageLoop in the thread proxy class, bind TaskRunner, and start MessageLoop
  • 4. Create a TaskRunners class to manage the four TaskRunners

ThreadHost

if (is_background_view) {
  thread_host_ = {thread_label, ThreadHost::Type::UI};
} else {
  thread_host_ = {thread_label, ThreadHost::Type::UI | ThreadHost::Type::GPU |
                                    ThreadHost::Type::IO};
}
Copy the code

The ThreadHost class defines an enumeration type for each of the four threads’ host objects:


enum Type {
  Platform = 1 << 0,
  UI = 1 << 1,
  GPU = 1 << 2,
  IO = 1 << 3};Copy the code

The constructor creates four thread C++ smart Pointers:

ThreadHost::ThreadHost(std: :string name_prefix, uint64_t mask) {
  if (mask & ThreadHost::Type::Platform) {
    platform_thread = std::make_unique<fml::Thread>(name_prefix + ".platform");
  }

  if (mask & ThreadHost::Type::UI) {
    ui_thread = std::make_unique<fml::Thread>(name_prefix + ".ui");
  }

  if (mask & ThreadHost::Type::GPU) {
    gpu_thread = std::make_unique<fml::Thread>(name_prefix + ".gpu");
  }

  if (mask & ThreadHost::Type::IO) {
    io_thread = std::make_unique<fml::Thread>(name_prefix + ".io"); }}Copy the code

MessageLoop

In engine/SRC/flutter/FML/thread. The cc in the constructor to create a thread class, initialize MessageLoop at the same time, the runner to the message queue associated tasks, Start the message queue loop.run (), which creates four different MessageLoop messages when the thread is created

Thread::Thread(const std: :string& name) : joined_(false) {
  fml::AutoResetWaitableEvent latch;
  fml::RefPtr<fml::TaskRunner> runner;
  thread_ = std::make_unique<std::thread>([&latch, &runner, name]() -> void {
    SetCurrentThreadName(name);
    fml::MessageLoop::EnsureInitializedForCurrentThread();// Initialize the message queue
    auto& loop = MessageLoop::GetCurrent();
    runner = loop.GetTaskRunner();
    latch.Signal();
    loop.Run();// Start the message queue
  });
  // The current thread wait state
  latch.Wait();
  task_runner_ = runner;
}
Copy the code

Platform Task Runner:

The Main Task Runner of the Flutter Engine is similar to the Android Main Thread or iOS Main Thread. But it’s important to note that there are differences.

Generally, when a Flutter application is started, an Engine instance is created. When the Engine is created, a thread is created for Platform Runner to use.

All interactions with the Flutter Engine (interface calls) must occur on the Platform Thread. Otherwise, unexpected exceptions may result. This is similar to how iOS UI operations must be performed on the main thread. Note that there are many modules in the Flutter Engine that are not thread-safe.

The rule is simple: All calls to the Flutter Engine interface must be made on the Platform Thread.

Blocking the Platform Thread does not directly cause the Flutter application to stall (unlike the iOS android main Thread). However, it is not recommended to perform heavy operations on the Runner. If the Platform Thread is stuck for a long time, it may be forcibly killed by the system Watchdog.

UI Task Runner Thread (Dart Runner)

The UI Task Runner is used to execute the Dart root ISOLATE code (the ISOLATE, which we’ll cover later, is simply the thread inside the Dart VM). The Root isolate is special in that it binds many of the functions that Flutter needs to perform rendering operations. For each frame, the engine does the following:

Root ISOLATE notifies the Flutter Engine that a frame needs to be rendered. The Flutter Engine notifies the platform that it needs to be notified at the next vsync. The platform waits for the next vSync to Layout the created objects and Widgets and generate a Layer Tree. This Tree is immediately submitted to the Flutter Engine. No rasterization is done in the current phase; this step simply generates a description of what needs to be drawn. Create or update a Tree that contains semantic information for displaying Widgets on the screen. This thing is mainly used to configure and render platform-specific auxiliary Accessibility elements. In addition to rendering logic, Root Isolate also handles messages from Native Plugins, Timers, Microtasks, and asynchronous IO. The Root Isolate is responsible for creating and managing the Layer Tree and ultimately deciding what to draw on the screen. Therefore, the overload of this thread will directly cause frame lag.

GPU Task Runner

GPU Task Runner Is used to execute GPU commands. The Layer Tree created by UI Task Runner is cross-platform and doesn’t care who does the drawing. GPU Task Runner is responsible for translating the information provided by Layer Tree into platform-executable GPU instructions. GPU Task Runner is also responsible for the management of GPU resources required for drawing. Resources mainly include platform Framebuffer, Surface, Texture and Buffers, etc.

Generally speaking UI Runner and GPU Runner run on different threads. GPU Runner will ask UI Runner for the data of the next frame according to the progress of the current frame execution, and may tell UI Runner to delay the task when the task is heavy. This scheduling mechanism ensures that THE GPU Runner is not overloaded, while avoiding unnecessary consumption of UI Runner.

It is recommended to create a dedicated GPU Runner thread for each Engine instance.

IO Task Runner

Several runners discussed earlier have high requirements for execution fluency. Overload of Platform Runner may cause system WatchDog to forcibly kill, while overload of UI and GPU Runner may cause lag of Flutter applications. But where do some of the necessary operations of the GPU thread, such as IO, go? The answer is IO Runner.

IO Runner’s main function is to read compressed image formats from image storage (such as disk) and process the image data in preparation for GPU Runner’s rendering. IO Runner starts by reading compressed image binary data (such as PNG and JPEG), decompressing it into a format that the GPU can process, and uploading the data to the GPU.

Obtaining resources such as UI. Image can only be called via an async call. When the call occurs, the Flutter Framework tells IO Runner to perform an asynchronous operation to load.

IO Runner directly determines that the loading delay of images and other resources indirectly affects performance. It is recommended to create a dedicated thread for IO Runner.

TaskRunner

ThreadHost created four threads, management Platform to create four TaskRunner, UI, GPU, IO thread in engine/SRC/flutter/FML task_runner. H

Provides four methods to handle the execution time of tasks submitted to MessageLoop and associated to message queues

  • PostTask
  • PostTaskForTime
  • PostDelayedTask
  • RunNowOrPostTask
  • RefPtr loop_
namespace fml {

class MessageLoopImpl;

class TaskRunner : public fml::RefCountedThreadSafe<TaskRunner> {
 public:
  virtual void PostTask(fml::closure task);

  virtual void PostTaskForTime(fml::closure task, fml::TimePoint target_time);

  virtual void PostDelayedTask(fml::closure task, fml::TimeDelta delay);

  virtual bool RunsTasksOnCurrentThread(a);

  virtual ~TaskRunner();

  static void RunNowOrPostTask(fml::RefPtr
       <:taskrunner>
         runner, fml::closure task)
       ;

 protected:
  TaskRunner(fml::RefPtr<MessageLoopImpl> loop);

 private:
  fml::RefPtr<MessageLoopImpl> loop_;

  FML_FRIEND_MAKE_REF_COUNTED(TaskRunner);
  FML_FRIEND_REF_COUNTED_THREAD_SAFE(TaskRunner);
  FML_DISALLOW_COPY_AND_ASSIGN(TaskRunner);
};

}  // namespace fml

#endif  // FLUTTER_FML_TASK_RUNNER_H_
Copy the code

TaskRunners

Create a TaskRunners that manages tasks in four threads

TaskRunners task_runners(thread_label,     // label
                                platform_runner,  // platform
                                gpu_runner,       // gpu
                                ui_runner,        // ui
                                io_runner         // io
Copy the code
namespaceBlink {record platform-related tasks of the four related threads unified management.class TaskRunners {
 public:
  TaskRunners(std: :string label,
              fml::RefPtr<fml::TaskRunner> platform, // Platform thread association
              fml::RefPtr<fml::TaskRunner> gpu,// Gpu thread association
              fml::RefPtr<fml::TaskRunner> ui,// the UI gets along with the association
              fml::RefPtr<fml::TaskRunner> io);/ / IO get along with.private:
  const std: :string label_;
  fml::RefPtr<fml::TaskRunner> platform_;
  fml::RefPtr<fml::TaskRunner> gpu_;
  fml::RefPtr<fml::TaskRunner> ui_;
  fml::RefPtr<fml::TaskRunner> io_;
};

}  // namespace blink

#endif  // FLUTTER_COMMON_TASK_RUNNERS_H_
Copy the code

Shell class initialization:

Shell class initialization, mainly responsible for the management of client resources/engine/SRC/flutter/Shell/platform/android/android_shell_holder. Cc, create

!!!!!!!!! Info “The main function of the Shell initializes the following four objects”

* platform_view_ = std::move(platform_view); * engine_ = std::move(engine); * rasterizer_ = std::move(rasterizer); * io_manager_ = std::move(io_manager); * Create the DartVMCopy the code

Main actions performed:

!!!!!!!!! – Waring “created a DartVM from scratch in new Shell”

  • 1. Record the start time
  • 2. Initialize log Settings
  • 3. Initialize Skia: InitSkiaEventTracer
  • 4. Initialize: SkGraphics
  • 5. Initialize the localization library :InitializeICU
  • 6. Create a virtual machine: blink: : DartVM: : ForProcess (Settings);
  • 7. Start platform tasks
  • new Shell
  • 7.2: A new DartVM was created in the new Shell:
  • 7.3 Install service protocol handlers.
  • 8. Actually creating platform operation object/engine/SRC/flutter/shell/platform/android/platform_view_android. Cc
  • 9. Create a CreateVSyncWaiter object
  • 10. Create the IOManager manager and execute it on the I/O thread
  • 11. Create Rasterizer execution on GPU thread
  • Create engine to execute in UI thread

Shell::Shell(blink::TaskRunners task_runners, blink::Settings settings)
: task_runners_(std::move(task_runners)),// Task runner
settings_(std::move(settings)),
vm_(blink::DartVM::ForProcess(settings_)) {// Create a new DartVM
FML_DCHECK(task_runners_.IsValid());
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
Copy the code

shell_ =
    Shell::Create(task_runners,             // task runners
                  settings_,                // settings
                  on_create_platform_view,  // platform view create callback
                  on_create_rasterizer      // rasterizer create callback); At Shell creation time:std: :unique_ptr<Shell> Shell::Create(
      blink::TaskRunners task_runners,
      blink::Settings settings,
      Shell::CreateCallback<PlatformView> on_create_platform_view,
      Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
    // Initialize the third-party library
    PerformInitializationTasks(settings);

    // Initialize the DartVM
    auto vm = blink::DartVM::ForProcess(settings);
    FML_CHECK(vm) << "Must be able to initialize the VM.";
    return Shell::Create(std::move(task_runners),             //
                         std::move(settings),                 //
                         vm->GetIsolateSnapshot(),            //
                         blink::DartSnapshot::Empty(),        //
                         std::move(on_create_platform_view),  //
                         std::move(on_create_rasterizer)      //
    );
  }

Copy the code

Initialize DartVM

DartVM::ForProcess

The Dart VM virtual machine when the Shell to create initialization: auto VM = blink: : DartVM: : ForProcess (Settings); , / engine/SRC/flutter/shell/common/shell. Cc, shell: : Create, Dart the analysis of the virtual machine in the subsequent extensions

  • 1. Load the DART VM snapshot
  • 2. Load the Isolate snapshot
  • 3. Invoke the DartVM constructor to initialize the VM
  fml::RefPtr<DartVM> DartVM::ForProcess(
    Settings settings,
    fml::RefPtr<DartSnapshot> vm_snapshot,
    fml::RefPtr<DartSnapshot> isolate_snapshot,
    fml::RefPtr<DartSnapshot> shared_snapshot) {
  std::lock_guard<std::mutex> lock(gVMMutex);
  std::call_once(gVMInitialization, [settings,          //
                                     vm_snapshot,       //
                                     isolate_snapshot,  //
                                     shared_snapshot    //] ()mutable {
    if(! vm_snapshot) { vm_snapshot = DartSnapshot::VMSnapshotFromSettings(settings); }if(! (vm_snapshot && vm_snapshot->IsValid())) { FML_LOG(ERROR) <<"VM snapshot must be valid.";
      return;
    }
    if(! isolate_snapshot) { isolate_snapshot = DartSnapshot::IsolateSnapshotFromSettings(settings); }if(! (isolate_snapshot && isolate_snapshot->IsValid())) { FML_LOG(ERROR) <<"Isolate snapshot must be valid.";
      return;
    }
    if(! shared_snapshot) { shared_snapshot = DartSnapshot::Empty(); } gVM = fml::MakeRefCounted<DartVM>(settings,//
                                      std::move(vm_snapshot),       //
                                      std::move(isolate_snapshot),  //
                                      std::move(shared_snapshot)    //
    );
  });
  return gVM;
  }

Copy the code

Where the third-party library is initialized when the Shell is created

PerformInitializationTasks,/engine/src/flutter/shell/common/shell.cc

  • RecordStartupTimestamp() Records the time stamp
  • FML ::SetLogSettings(log_settings) Sets log information
  • InitSkiaEventTracer(settings.trace_skia) initializes the Skia2d image engine library tracker
  • SkGraphics::Init(); Initialize the 2D graphics engine library
  • fml::icu::InitializeICU(settings.icu_data_path); Initialize internationalization processing ICU
// Though there can be multiple shells, some settings apply to all components in
// the process. These have to be setup before the shell or any of its
// sub-components can be initialized. In a perfect world, this would be empty.
// TODO(chinmaygarde): The unfortunate side effect of this call is that settings
// that cause shell initialization failures will still lead to some of their
// settings being applied.
static void PerformInitializationTasks(const blink::Settings& settings) {
  static std::once_flag gShellSettingsInitialization = {};
  std::call_once(gShellSettingsInitialization, [&settings] {
    RecordStartupTimestamp();

    {
      fml::LogSettings log_settings;
      log_settings.min_log_level =
          settings.verbose_logging ? fml::LOG_INFO : fml::LOG_ERROR;
      fml::SetLogSettings(log_settings);
    }

    tonic::SetLogHandler(
        [](const char* message) { FML_LOG(ERROR) << message; });

    if (settings.trace_skia) {
      InitSkiaEventTracer(settings.trace_skia);
    }

    if(! settings.skia_deterministic_rendering_on_cpu) { SkGraphics::Init(); }else {
      FML_DLOG(INFO) << "Skia deterministic rendering is enabled.";
    }

    if (settings.icu_initialization_required) {
      if(settings.icu_data_path.size() ! =0) {
        fml::icu::InitializeICU(settings.icu_data_path);
      } else if (settings.icu_mapper) {
        fml::icu::InitializeICUFromMapping(settings.icu_mapper());
      } else {
        FML_DLOG(WARNING) << "Skipping ICU initialization in the shell."; }}}); }Copy the code

CreateShellOnPlatformThread

Shell to create needed in this class is initialized CreateShellOnPlatformThread for Shell corresponding platefrom, IO, GPU, UI, / engine/SRC/flutter/Shell/common/Shell. The cc, The following classes focus on the arguments passed in the constructor to help you understand the related logic calls!! WARNING “The following code snippet is where the object is actually initialized”


std: :unique_ptr<Shell> Shell::Create(
    blink::TaskRunners task_runners,
    blink::Settings settings,
    fml::RefPtr<blink::DartSnapshot> isolate_snapshot,
    fml::RefPtr<blink::DartSnapshot> shared_snapshot,
    Shell::CreateCallback<PlatformView> on_create_platform_view,
    Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
  PerformInitializationTasks(settings);

  if(! task_runners.IsValid() || ! on_create_platform_view || ! on_create_rasterizer) {return nullptr;
  }

  fml::AutoResetWaitableEvent latch;
  std: :unique_ptr<Shell> shell;
  fml::TaskRunner::RunNowOrPostTask(// Submit the task to the Platform thread to run
      task_runners.GetPlatformTaskRunner(),
      [&latch,                                          //
       &shell,                                          //
       task_runners = std::move(task_runners),          //
       settings,                                        //
       isolate_snapshot = std::move(isolate_snapshot),  //
       shared_snapshot = std::move(shared_snapshot),    //
       on_create_platform_view,                         //
       on_create_rasterizer                             //
  ]() {
        shell = CreateShellOnPlatformThread(std::move(task_runners),      //
                                            settings,                     //
                                            std::move(isolate_snapshot),  //
                                            std::move(shared_snapshot),   //
                                            on_create_platform_view,      //
                                            on_create_rasterizer          //
        );
        latch.Signal();
      });
  latch.Wait();
  return shell;
}
Copy the code

CreateShellOnPlatformThread ` complete Shell points of the initial information

  • 1. Create a Shell instance object ‘auto Shell = STD ::unique_ptr(new Shell(task_runners, Settings));
  • Auto platform_view = on_create_platform_view(*shell.get()));
  • Create a Syncwaiter ‘auto vsync_waiter = platform_view->CreateVSyncWaiter();
  • 4. Create an IO management thread ‘STD ::unique_ptr io_manager;
  • 5. Create engine on the UI thread: ` FML: : AutoResetWaitableEvent ui_latch;

std: :unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
  blink::TaskRunners task_runners,
  blink::Settings settings,
  fml::RefPtr<blink::DartSnapshot> isolate_snapshot,
  fml::RefPtr<blink::DartSnapshot> shared_snapshot,
  Shell::CreateCallback<PlatformView> on_create_platform_view,
  Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
if(! task_runners.IsValid()) {return nullptr;
}

auto shell = std: :unique_ptr<Shell>(new Shell(task_runners, settings));

// Create the platform view on the platform thread (this thread).
auto platform_view = on_create_platform_view(*shell.get());
if(! platform_view || ! platform_view->GetWeakPtr()) {return nullptr;
}

// Ask the platform view for the vsync waiter. This will be used by the engine
// to create the animator.
auto vsync_waiter = platform_view->CreateVSyncWaiter();
if(! vsync_waiter) {return nullptr;
}

// Create the IO manager on the IO thread. The IO manager must be initialized
// first because it has state that the other subsystems depend on. It must
// first be booted and the necessary references obtained to initialize the
// other subsystems.
fml::AutoResetWaitableEvent io_latch;
std: :unique_ptr<IOManager> io_manager;
auto io_task_runner = shell->GetTaskRunners().GetIOTaskRunner();
fml::TaskRunner::RunNowOrPostTask(
    io_task_runner,
    [&io_latch,       //
     &io_manager,     //
     &platform_view,  //
     io_task_runner   //
]() {
      io_manager = std::make_unique<IOManager>(
          platform_view->CreateResourceContext(), io_task_runner);
      io_latch.Signal();
    });
io_latch.Wait();

// Create the rasterizer on the GPU thread.
fml::AutoResetWaitableEvent gpu_latch;
std: :unique_ptr<Rasterizer> rasterizer;
fml::WeakPtr<blink::SnapshotDelegate> snapshot_delegate;
fml::TaskRunner::RunNowOrPostTask(
    task_runners.GetGPUTaskRunner(), [&gpu_latch,            //
                                      &rasterizer,           //
                                      on_create_rasterizer,  //
                                      shell = shell.get(),   //
                                      &snapshot_delegate     //] () {if (auto new_rasterizer = on_create_rasterizer(*shell)) {
        rasterizer = std::move(new_rasterizer);
        snapshot_delegate = rasterizer->GetSnapshotDelegate();
      }
      gpu_latch.Signal();
    });

gpu_latch.Wait();

// Create the engine on the UI thread.
fml::AutoResetWaitableEvent ui_latch;
std: :unique_ptr<Engine> engine;
fml::TaskRunner::RunNowOrPostTask(
    shell->GetTaskRunners().GetUITaskRunner(),
    fml::MakeCopyable([&ui_latch,                                         //
                       &engine,                                           //
                       shell = shell.get(),                               //
                       isolate_snapshot = std::move(isolate_snapshot),    //
                       shared_snapshot = std::move(shared_snapshot),      //
                       vsync_waiter = std::move(vsync_waiter),            //
                       snapshot_delegate = std::move(snapshot_delegate),  //
                       io_manager = io_manager->GetWeakPtr()              //] ()mutable {
      const auto& task_runners = shell->GetTaskRunners();

      // The animator is owned by the UI thread but it gets its vsync pulses
      // from the platform.
      auto animator = std::make_unique<Animator>(*shell, task_runners,
                                                 std::move(vsync_waiter));

      engine = std::make_unique<Engine>(*shell,                        //
                                        shell->GetDartVM(),            //
                                        std::move(isolate_snapshot),   //
                                        std::move(shared_snapshot),    //
                                        task_runners,                  //
                                        shell->GetSettings(),          //
                                        std::move(animator),           //
                                        std::move(snapshot_delegate),  //
                                        std::move(io_manager)          //
      );
      ui_latch.Signal();
    }));

ui_latch.Wait();
// We are already on the platform thread. So there is no platform latch to
// wait on.

if(! shell->Setup(std::move(platform_view),  //
                  std::move(engine),         //
                  std::move(rasterizer),     //
                  std::move(io_manager))     //
) {
  return nullptr;
}

return shell;
}

Copy the code

Set the Shell management Platform of thread management related resources: / engine/SRC/flutter/Shell/common/engine. The cc/engine/SRC/flutter/Shell/common/Shell. Creat cc in execution Called in the eShellOnPlatformThread method

  • 1.PlatformView: Mainly manages related view events
  • 2.Engine: All resources are ready and dart code and DART VIRTUAL machine are invoked for code execution
  • 3.Rasterizer: Rasterizer mainly deals with GPU-related events
  • 4.IOManager: Manages I/O threads
  • 5. Set DartVM ServiceProtocol Settings to handle callback
  • 6.PersistentCache::GetCacheForProcess()->AddWorkerTaskRunner(task_runners_.GetIOTaskRunner()); Processing of cached directories
bool Shell::Setup(std: :unique_ptr<PlatformView> platform_view,
                  std: :unique_ptr<Engine> engine,
                  std: :unique_ptr<Rasterizer> rasterizer,
                  std: :unique_ptr<IOManager> io_manager) {
  if (is_setup_) {
    return false;
  }

  if(! platform_view || ! engine || ! rasterizer || ! io_manager) {return false;
  }

  platform_view_ = std::move(platform_view);
  engine_ = std::move(engine);
  rasterizer_ = std::move(rasterizer);
  io_manager_ = std::move(io_manager);

  is_setup_ = true;

  if (auto vm = blink::DartVM::ForProcessIfInitialized()) {
    vm->GetServiceProtocol().AddHandler(this, GetServiceProtocolDescription());
  }

  PersistentCache::GetCacheForProcess()->AddWorkerTaskRunner(
      task_runners_.GetIOTaskRunner());

  return true;
}
Copy the code

Create the platform

// Create the platform view on the platform thread (this thread).
auto platform_view = on_create_platform_view(*shell.get());
if(! platform_view || ! platform_view->GetWeakPtr()) {return nullptr;
}
Copy the code

CreateVSyncWaiter

// Ask the platform view for the vsync waiter. This will be used by the engine
// to create the animator.
auto vsync_waiter = platform_view->CreateVSyncWaiter();
if(! vsync_waiter) {return nullptr;
}
Copy the code

Create the IO manager on the IO thread

// Create the IO manager on the IO thread. The IO manager must be initialized
// first because it has state that the other subsystems depend on. It must
// first be booted and the necessary references obtained to initialize the
// other subsystems.
fml::AutoResetWaitableEvent io_latch;
std: :unique_ptr<IOManager> io_manager;
auto io_task_runner = shell->GetTaskRunners().GetIOTaskRunner();
fml::TaskRunner::RunNowOrPostTask(
    io_task_runner,
    [&io_latch,       //
     &io_manager,     //
     &platform_view,  //
     io_task_runner   //
]() {
      io_manager = std::make_unique<IOManager>(
          platform_view->CreateResourceContext(), io_task_runner);
      io_latch.Signal();
    });
io_latch.Wait();

Copy the code

Create the rasterizer on the GPU thread

// Create the rasterizer on the GPU thread.
fml::AutoResetWaitableEvent gpu_latch;
std: :unique_ptr<Rasterizer> rasterizer;
fml::WeakPtr<blink::SnapshotDelegate> snapshot_delegate;
fml::TaskRunner::RunNowOrPostTask(
    task_runners.GetGPUTaskRunner(), [&gpu_latch,            //
                                      &rasterizer,           //
                                      on_create_rasterizer,  //
                                      shell = shell.get(),   //
                                      &snapshot_delegate     //] () {if (auto new_rasterizer = on_create_rasterizer(*shell)) {
        rasterizer = std::move(new_rasterizer);
        snapshot_delegate = rasterizer->GetSnapshotDelegate();
      }
      gpu_latch.Signal();
    });

gpu_latch.Wait();
Copy the code

Create the engine on the UI thread

// Create the engine on the UI thread.
fml::AutoResetWaitableEvent ui_latch;
std: :unique_ptr<Engine> engine;
fml::TaskRunner::RunNowOrPostTask(
    shell->GetTaskRunners().GetUITaskRunner(),
    fml::MakeCopyable([&ui_latch,                                         //
                       &engine,                                           //
                       shell = shell.get(),                               //
                       isolate_snapshot = std::move(isolate_snapshot),    //
                       shared_snapshot = std::move(shared_snapshot),      //
                       vsync_waiter = std::move(vsync_waiter),            //
                       snapshot_delegate = std::move(snapshot_delegate),  //
                       io_manager = io_manager->GetWeakPtr()              //] ()mutable {
      const auto& task_runners = shell->GetTaskRunners();

      // The animator is owned by the UI thread but it gets its vsync pulses
      // from the platform.
      auto animator = std::make_unique<Animator>(*shell, task_runners,
                                                 std::move(vsync_waiter));

      engine = std::make_unique<Engine>(*shell,                        //
                                        shell->GetDartVM(),            //
                                        std::move(isolate_snapshot),   //
                                        std::move(shared_snapshot),    //
                                        task_runners,                  //
                                        shell->GetSettings(),          //
                                        std::move(animator),           //
                                        std::move(snapshot_delegate),  //
                                        std::move(io_manager)          //
      );
      ui_latch.Signal();
    }));

ui_latch.Wait();
Copy the code

Engine initialization

Engine::Engine(Delegate& delegate,
               blink::DartVM& vm,
               fml::RefPtr<blink::DartSnapshot> isolate_snapshot,
               fml::RefPtr<blink::DartSnapshot> shared_snapshot,
               blink::TaskRunners task_runners,
               blink::Settings settings,
               std: :unique_ptr<Animator> animator,
               fml::WeakPtr<blink::SnapshotDelegate> snapshot_delegate,
               fml::WeakPtr<blink::IOManager> io_manager)
    : delegate_(delegate),
      settings_(std::move(settings)),
      animator_(std::move(animator)),
      activity_running_(false),
      have_surface_(false),
      weak_factory_(this) {
  // Runtime controller is initialized here because it takes a reference to this
  // object as its delegate. The delegate may be called in the constructor and
  // we want to be fully initilazed by that point.
  runtime_controller_ = std::make_unique<blink::RuntimeController>(
      *this.// runtime delegate
      &vm,                                   // VM
      std::move(isolate_snapshot),           // isolate snapshot
      std::move(shared_snapshot),            // shared snapshot
      std::move(task_runners),               // task runners
      std::move(snapshot_delegate),          // snapshot delegate
      std::move(io_manager),                 // io manager
      settings_.advisory_script_uri,         // advisory script uri
      settings_.advisory_script_entrypoint,  // advisory script entrypoint
      settings_.idle_notification_callback   // idle notification callback
  );
}
Copy the code

RuntimeController&WindowClient&Window

RuntimeController::RuntimeController(
    RuntimeDelegate& p_client,
    DartVM* p_vm,
    fml::RefPtr<DartSnapshot> p_isolate_snapshot,
    fml::RefPtr<DartSnapshot> p_shared_snapshot,
    TaskRunners p_task_runners,
    fml::WeakPtr<SnapshotDelegate> p_snapshot_delegate,
    fml::WeakPtr<IOManager> p_io_manager,
    std: :string p_advisory_script_uri,
    std: :string p_advisory_script_entrypoint,
    std::function<void(int64_t)> p_idle_notification_callback)
    : RuntimeController(p_client,
                        p_vm,
                        std::move(p_isolate_snapshot),
                        std::move(p_shared_snapshot),
                        std::move(p_task_runners),
                        std::move(p_snapshot_delegate),
                        std::move(p_io_manager),
                        std::move(p_advisory_script_uri),
                        std::move(p_advisory_script_entrypoint),
                        p_idle_notification_callback,
                        WindowData{/* default window data */}) {}

RuntimeController::RuntimeController(
    RuntimeDelegate& p_client,
    DartVM* p_vm,
    fml::RefPtr<DartSnapshot> p_isolate_snapshot,
    fml::RefPtr<DartSnapshot> p_shared_snapshot,
    TaskRunners p_task_runners,
    fml::WeakPtr<SnapshotDelegate> p_snapshot_delegate,
    fml::WeakPtr<IOManager> p_io_manager,
    std: :string p_advisory_script_uri,
    std: :string p_advisory_script_entrypoint,
    std::function<void(int64_t)> idle_notification_callback,
    WindowData p_window_data)
    : client_(p_client),
      vm_(p_vm),
      isolate_snapshot_(std::move(p_isolate_snapshot)),
      shared_snapshot_(std::move(p_shared_snapshot)),
      task_runners_(p_task_runners),
      snapshot_delegate_(p_snapshot_delegate),
      io_manager_(p_io_manager),
      advisory_script_uri_(p_advisory_script_uri),
      advisory_script_entrypoint_(p_advisory_script_entrypoint),
      idle_notification_callback_(idle_notification_callback),
      window_data_(std::move(p_window_data)),
      root_isolate_(
          DartIsolate::CreateRootIsolate(vm_,
                                         isolate_snapshot_,
                                         shared_snapshot_,
                                         task_runners_,
                                         std::make_unique<Window>(this),
                                         snapshot_delegate_,
                                         io_manager_,
                                         p_advisory_script_uri,
                                         p_advisory_script_entrypoint)) {
  std: :shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
  root_isolate->SetReturnCodeCallback([this] (uint32_t code) {
    root_isolate_return_code_ = {true, code}; }); The current object is a ClientWidow object, and DidCreateIsolate is called to load the DART :UI libraryif (auto* window = GetWindowIfAvailable()) {
    tonic::DartState::Scope scope(root_isolate);
    window->DidCreateIsolate();
    if(! FlushRuntimeStateToIsolate()) { FML_DLOG(ERROR) <<"Could not setup intial isolate state."; }}else {
    FML_DCHECK(false) < <"RuntimeController created without window binding.";
  }
  FML_DCHECK(Dart_CurrentIsolate() == nul
};

}  // namespace blink

#endif  // FLUTTER_RUNTIME_RUNTIME_CONTROLLER_H_

Copy the code

DartIsolate

Call shared_embedder_isolate – > SetWindow (STD: : move (Windows)); The object passes the RuntimeController to the Window class for binding


std::weak_ptr<DartIsolate> DartIsolate::CreateRootIsolate(
    DartVM* vm,
    fml::RefPtr<DartSnapshot> isolate_snapshot,
    fml::RefPtr<DartSnapshot> shared_snapshot,
    TaskRunners task_runners,
    std: :unique_ptr<Window> window,
    fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
    fml::WeakPtr<IOManager> io_manager,
    std: :string advisory_script_uri,
    std: :string advisory_script_entrypoint,
    Dart_IsolateFlags* flags) {
  TRACE_EVENT0("flutter"."DartIsolate::CreateRootIsolate");
  Dart_Isolate vm_isolate = nullptr;
  std::weak_ptr<DartIsolate> embedder_isolate;

  char* error = nullptr;

  // Since this is the root isolate, we fake a parent embedder data object. We
  // cannot use unique_ptr here because the destructor is private (since the
  // isolate lifecycle is entirely managed by the VM).
  auto root_embedder_data = std::make_unique<std: :shared_ptr<DartIsolate>>(
      std::make_shared<DartIsolate>(
          vm,                            // VM
          std::move(isolate_snapshot),   // isolate snapshot
          std::move(shared_snapshot),    // shared snapshot
          task_runners,                  // task runners
          std::move(snapshot_delegate),  // snapshot delegate
          std::move(io_manager),         // IO manager
          advisory_script_uri,           // advisory URI
          advisory_script_entrypoint,    // advisory entrypoint
          nullptr  // child isolate preparer will be set when this isolate is
                   // prepared to run
          ));

  std::tie(vm_isolate, embedder_isolate) = CreateDartVMAndEmbedderObjectPair(
      advisory_script_uri.c_str(),         // advisory script URI
      advisory_script_entrypoint.c_str(),  // advisory script entrypoint
      nullptr.// package root
      nullptr.// package config
      flags,                               // flags
      root_embedder_data.get(),            // parent embedder data
      true.// is root isolate
      &error                               // error (out)
  );

  if(error ! =nullptr) {
    free(error);
  }

  if (vm_isolate == nullptr) {
    return {};
  }

  std: :shared_ptr<DartIsolate> shared_embedder_isolate =
      embedder_isolate.lock();
  if (shared_embedder_isolate) {
    // Only root isolates can interact with windows.
    shared_embedder_isolate->SetWindow(std::move(window));
  }

  root_embedder_data.release();

  returnembedder_isolate; }}Copy the code

Window class initialization process

CreateRootIsolate creates a RootIsolate object

RuntimeController::RuntimeController(.....) : client_(p_client), .......) , window_data_(std::move(p_window_data)),
      root_isolate_(
          DartIsolate::CreateRootIsolate(vm_,
                                         isolate_snapshot_,
                                         shared_snapshot_,
                                         task_runners_,
                                         std::make_unique<Window>(this),
                                         snapshot_delegate_,
                                         io_manager_,
                                         p_advisory_script_uri,
                                         p_advisory_script_entrypoint)) {
  std: :shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
  root_isolate->SetReturnCodeCallback([this] (uint32_t code) {
    root_isolate_return_code_ = {true, code}; }); ## Window class initializationif (auto* window = GetWindowIfAvailable()) {
    tonic::DartState::Scope scope(root_isolate);
    window->DidCreateIsolate();
    if(! FlushRuntimeStateToIsolate()) { FML_DLOG(ERROR) <<"Could not setup intial isolate state."; }}else {
    FML_DCHECK(false) < <"RuntimeController created without window binding.";
  }
  FML_DCHECK(Dart_CurrentIsolate() == nullptr);
}
Copy the code

Android Native layer communicates with libFlutter:

After analyzing the entire initialization process, follow the following diagram to analyze the entire call process and the initialization process of the above code, which helps to understand the initialization of the entire runtime environment related classes and functions and logic

flutterplugin1.png

Android calls the code of the JNI layer, uses the local interface to communicate with the FlutterJNI engine, and uses the relevant local methods of FlutterJNI in Flutter for Android. Platform_view_android_jni initializes the so library the first time it is loaded:

/io/flutter/embedding/engine/FlutterJNI.class engine/src/flutter/shell/platform/android/platform_view_android_jni.cc

public class FlutterJNI {
    @UiThread
    public static native boolean nativeGetIsSoftwareRenderingEnabled(a);
    @UiThread
    public static native String nativeGetObservatoryUri(a);
    private native void nativeSurfaceCreated(long var1, Surface var3);
    private native void nativeSurfaceChanged(long var1, int var3, int var4);
    private native void nativeSurfaceDestroyed(long var1);
    private native void nativeSetViewportMetrics(long var1, float var3, int var4, int var5, int var6, int var7, int var8, int var9, int var10, int var11, int var12, int var13);
    private native Bitmap nativeGetBitmap(long var1);
    private native void nativeDispatchPointerDataPacket(long var1, ByteBuffer var3, int var4);
    private native void nativeDispatchSemanticsAction(long var1, int var3, int var4, ByteBuffer var5, int var6);
    private native void nativeSetSemanticsEnabled(long var1, boolean var3);
    private native void nativeSetAccessibilityFeatures(long var1, int var3);
    private native void nativeRegisterTexture(long var1, long var3, SurfaceTexture var5);
    private native void nativeMarkTextureFrameAvailable(long var1, long var3);
    private native void nativeUnregisterTexture(long var1, long var3);
    private native long nativeAttach(FlutterJNI var1, boolean var2);
    private native void nativeDetach(long var1);
    private native void nativeDestroy(long var1);
    private native void nativeRunBundleAndSnapshotFromLibrary(long var1, @NonNull String[] var3, @Nullable String var4, @Nullable String var5, @NonNull AssetManager var6);
    private native void nativeDispatchEmptyPlatformMessage(long var1, String var3, int var4);
    private native void nativeDispatchPlatformMessage(long var1, String var3, ByteBuffer var4, int var5, int var6);
    private native void nativeInvokePlatformMessageEmptyResponseCallback(long var1, int var3);
    private native void nativeInvokePlatformMessageResponseCallback(long var1, int var3, ByteBuffer var4, int var5);
}
Copy the code

Engine used in dynamic JNI yuan code registration related methods: engine/SRC/flutter/shell/platform/android/platform_view_android_jni. Cc

Call the Register method to Register local methods:

bool RegisterApi(JNIEnv* env) {
static const JNINativeMethod flutter_jni_methods[] = {
  // Start of methods from FlutterNativeView
  {
      .name = "nativeAttach",
      .signature = "(Lio/flutter/embedding/engine/FlutterJNI; Z)J",
      .fnPtr = reinterpret_cast<void*>(&shell::AttachJNI),
  },
  {
      .name = "nativeDestroy",
      .signature = "(J)V",
      .fnPtr = reinterpret_cast<void*>(&shell::DestroyJNI),
  },
  {
      .name = "nativeRunBundleAndSnapshotFromLibrary",
      .signature = "(J[Ljava/lang/String;Ljava/lang/String;"
                   "Ljava/lang/String; Landroid/content/res/AssetManager;) V",
      .fnPtr =
          reinterpret_cast<void*>(&shell::RunBundleAndSnapshotFromLibrary),
  },
};

if(env->RegisterNatives(g_flutter_jni_class->obj(), flutter_jni_methods, arraysize(flutter_jni_methods)) ! =0) {
FML_LOG(ERROR) << "Failed to RegisterNatives with FlutterJNI";
return false;
}
Copy the code
` engine/SRC/flutter/shell/common/shell. The cc ` as a central control function, using weak references to save PlatformView, Android, Ios stored using shell under the Platform of Platefrom implementation to handle the related View Platform, shell initialization is ` engine/SRC/flutter/shell/Platform/android/android_shell_holde R.c c `, ` FlutterMain: : Get () GetSettings configuration file () ` compile time ` engine/SRC/flutter/common/Settings. The cc `, ` flutterJNI ` is android code, 'is_background_view' is in the Java layer FlutterNativeView, which is Java and JNI communication, data transmission logic processing, FlutterNativeView constructor calls JNI code, Initialize 'android_shell_holder' using this class to complete the 'Shell' class### SurfaceView initialization

### Java SurfaceView initializationGetFlutterJNI Initializes SurfaceView Java this.mSurfaceCallback = newCallback() { public void surfaceCreated(SurfaceHolder holder) { FlutterView.this.assertAttached(); FlutterView.this.mNativeView.getFlutterJNI().onSurfaceCreated(holder.getSurface()); } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { FlutterView.this.assertAttached(); FlutterView.this.mNativeView.getFlutterJNI().onSurfaceChanged(width, height); } public void surfaceDestroyed(SurfaceHolder holder) { FlutterView.this.assertAttached(); FlutterView.this.mNativeView.getFlutterJNI().onSurfaceDestroyed(); }};Copy the code

JNI initializes the SurfaceView

/Users/cangck/engine/src/flutter/shell/platform/android/platform_view_android_jni.cc

SurfaceCreated

static void SurfaceCreated(JNIEnv* env, jobject jcaller, jlong shell_holder, jobject jsurface) {
  // Note: This frame ensures that any local references used by
  // ANativeWindow_fromSurface are released immediately. This is needed as a
  // workaround for https://code.google.com/p/android/issues/detail?id=68174
  fml::jni::ScopedJavaLocalFrame scoped_local_reference_frame(env);
  auto window = fml::MakeRefCounted<AndroidNativeWindow>(
      ANativeWindow_fromSurface(env, jsurface));
  ANDROID_SHELL_HOLDER->GetPlatformView()->NotifyCreated(std::move(window));
}
Copy the code

SurfaceChanged

static void SurfaceChanged(JNIEnv* env, jobject jcaller, jlong shell_holder, jint width, jint height) {
  ANDROID_SHELL_HOLDER->GetPlatformView()->NotifyChanged(
      SkISize::Make(width, height));
}

Copy the code

SurfaceDestroyed

static void SurfaceDestroyed(JNIEnv* env, jobject jcaller, jlong shell_holder) {
  ANDROID_SHELL_HOLDER->GetPlatformView()->NotifyDestroyed();
}
Copy the code

conclusion

From the above analysis, we have an overview of how Android starts and initializes the Flutter engine: 2. After libFlutter. So is loaded, the JNI_onLoad method callback starts to initialize the engine 4.PlatformViewandroid initialization, processing surfaceView-related image rendering interface 5.FlutterView initialization, Call the local method to add the SurfaceView to libFlutter. So to associate 6.AttachJNI method starts to initialize Dart 7 9. 10 DartVM started. Engine initialization 12. Initialize the Window class 13 of the FlutterUI interface. After the above steps, the initialization of the Flutterengine has been completed. The general process and framework have been completed. A general outline of Flutterengine can be seen, which will be optimized, learned and supplemented in the subsequent work

In learning a new language, mainly to study the overall logic, not too attention to detail, contour after touch clear, in the subsequent development of the brain has a framework, the problem of rapid positioning is where the problem, check the source code, is constantly developing perfect details, no one can be done at once all the questions, The framework knows how much time it can take to speed up development and deal with bugs later in the development process.

Persistent, step by step – mutual encouragement