This article is based on flutter 1.17.5 analysis

I. Initialization of FlutterApplication

FutterApplication and MainActivity are configured in the Androdmanifester. XML of the Flutter project, so let’s look at what happens in FlutterApplication when the application starts.

FlutterApplication->onCreate
    FlutterMain.startInitialization
    	FlutterLoader.getInstance().startInitialization
    
public void startInitialization(@NonNull Context applicationContext, @NonNull FlutterLoader.Settings settings) {
    if (this.settings == null) {
        if(Looper.myLooper() ! = Looper.getMainLooper()) {throw new IllegalStateException("startInitialization must be called on the main thread");
        } else {
            applicationContext = applicationContext.getApplicationContext();
            this.settings = settings;
            long initStartTimestampMillis = SystemClock.uptimeMillis();
            this.initConfig(applicationContext);
            this.initResources(applicationContext);
            System.loadLibrary("flutter");
            VsyncWaiter.getInstance((WindowManager)applicationContext.getSystemService("window")).init();
            longinitTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis; FlutterJNI.nativeRecordStartTimestamp(initTimeMillis); }}}Copy the code

The FlutterApplication does the following during initialization:

  1. InitConfig Indicates the initial configuration
  2. InitResources Initializes resource information
  3. System.loadLibrary(“flutter”); Load the Flutter Native library and register the JNI method
  4. VsyncWaiter. GetInstance ((WindowManager) applicationContext. GetSystemService (” window “)). The init () by WM initialization VsyncWatier
1.1 Initial Configuration
private void initConfig(@NonNull Context applicationContext) {
    Bundle metadata = this.getApplicationInfo(applicationContext).metaData;
    if(metadata ! =null) {
        this.aotSharedLibraryName = metadata.getString(PUBLIC_AOT_SHARED_LIBRARY_NAME, "libapp.so");
        this.flutterAssetsDir = metadata.getString(PUBLIC_FLUTTER_ASSETS_DIR_KEY, "flutter_assets");
        this.vmSnapshotData = metadata.getString(PUBLIC_VM_SNAPSHOT_DATA_KEY, "vm_snapshot_data");
        this.isolateSnapshotData = metadata.getString(PUBLIC_ISOLATE_SNAPSHOT_DATA_KEY, "isolate_snapshot_data"); }}Copy the code

Initialize variables, including the shared library name of AOT, the Asscets directory of FLUTTER, the snapshot data name of VM, and the snapshot data name of ISOLATE.

1.2 Initializing Resource Information
  private void initResources(@NonNull Context applicationContext) {(new ResourceCleaner(applicationContext)).start();
        String dataDirPath = PathUtils.getDataDirectory(applicationContext);
        String packageName = applicationContext.getPackageName();
        PackageManager packageManager = applicationContext.getPackageManager();
        AssetManager assetManager = applicationContext.getResources().getAssets();
        this.resourceExtractor = new ResourceExtractor(dataDirPath, packageName, packageManager, assetManager);
        this.resourceExtractor.addResource(this.fullAssetPathFrom(this.vmSnapshotData)).
          addResource(this.fullAssetPathFrom(this.isolateSnapshotData)).addResource(this.fullAssetPathFrom("kernel_blob.bin"));
        this.resourceExtractor.start();
 }
Copy the code

Get the Android package manager, then get the AssetManager to get the resource manager object, and finally add the resource file of flutter to the resource manager via addResource of ResourceExtractor.

1.3 Load the flutter library

The analysis of the Flutter native library requires a separate download of the engine code. When the SO library is loaded, it calls its internal JNI_OnLoad method. Here we first look at what the Flutter library does at the JNI layer.

// shell/platform/android/library_loader.cc
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
  // Initialize the Java VM.
  fml::jni::InitJavaVM(vm);

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

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

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

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

  return JNI_VERSION_1_4;
}
Copy the code

You can see the following operations in JNI_OnLoad:

  1. InitJavaVM Initializes the JavaVM
  2. Registered FlutterMain
  3. Registered PlatformViewAndroid
  4. Registered VsyncWaiter
1.3.1 Initializing the Java VM
// fml/platform/android/jni_util.cc
static JavaVM* g_jvm = nullptr;

void InitJavaVM(JavaVM* vm) {
  FML_DCHECK(g_jvm == nullptr);
  g_jvm = vm;
}
Copy the code

We just store JavaVm virtual machine instance objects in the global G_JVM. We know that When Android creates an application process, it creates a JavaVm object for it through Zygote’s fork, which is where the JavaVm object instances come from.

1.3.2 registered FlutterMain
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;
}
Copy the code

By registering here two jni native methods nativeInit and nativePrefetchDefaultFontManager, respectively correspond to the Init method and PrefetchDefaultFontManager FlutterMain.

1.3.3 registered PlatformViewAndroid
// shell/platform/android/platform_view_android_jni_impl.cc
bool PlatformViewAndroid::Register(JNIEnv* env) {... 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; }...return RegisterApi(env);
}

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

  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"); . g_handle_platform_message_response_method = env->GetMethodID(
      g_flutter_jni_class->obj(), "handlePlatformMessageResponse"."(I[B)V"); . g_on_first_frame_method = env->GetMethodID(g_flutter_jni_class->obj(), "onFirstFrame"."()V"); . g_on_engine_restart_method = env->GetMethodID(g_flutter_jni_class->obj(), "onPreEngineRestart"."()V"); . g_create_overlay_surface_method = env->GetMethodID(g_flutter_jni_class->obj(), "createOverlaySurface"."()Lio/flutter/embedding/engine/FlutterOverlaySurface;"); .return true;
}
Copy the code

PlateformView registers a bunch of Java object methods for c++ to call Java layer methods, and registers classes’ JNI methods through the RegisterApi for the Java layer to call c++ methods.

1.3.4 registered VsyncWaiter
// shell/platform/android/vsync_waiter_android.cc
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;
}
Copy the code

VsyncWaiter registers the nativeOnVsync method in the JNI layer through the Register, and the corresponding native method of this method is OnNativeVsync. Meanwhile, it obtains the asyncWaitForVsync method of The FlutterJNI class in the Java layer.

Initialization of FlutterActivity

MainActivity in androdmanifest.xml inherits from FlutterActivity.

class MainActivity: FlutterActivity(a){}
Copy the code

Its default implementation is empty, so we’ll focus on the internal implementation of FlutterActivity.

public class FlutterActivity extends Activity implements Host.LifecycleOwner {
    @VisibleForTesting
    protectedFlutterActivityAndFragmentDelegate delegate; .protected void onCreate(@Nullable Bundle savedInstanceState) {
        this.switchLaunchThemeForNormalTheme();
        super.onCreate(savedInstanceState);
        this.lifecycle.handleLifecycleEvent(Event.ON_CREATE);
        this.delegate = new FlutterActivityAndFragmentDelegate(this);
        this.delegate.onAttach(this);
        this.delegate.onActivityCreated(savedInstanceState);
        this.configureWindowForTransparency();
        this.setContentView(this.createFlutterView());
        this.configureStatusBarForFullscreenFlutterExperience();
    }
    
    protected void onStart(a) {
        super.onStart();
        this.lifecycle.handleLifecycleEvent(Event.ON_START);
        this.delegate.onStart();
    }

    protected void onResume(a) {
        super.onResume();
        this.lifecycle.handleLifecycleEvent(Event.ON_RESUME);
        this.delegate.onResume(); }...protected void onStop(a) {
        super.onStop();
        this.delegate.onStop();
        this.lifecycle.handleLifecycleEvent(Event.ON_STOP); }... }Copy the code

From the code structure, FlutterActivity entrust the life cycle of a object, called FlutterActivityAndFragmentDelegate in onCreate method to create it. At the same time, onAttach and onActivityCreated methods are called after creation. The Activity is then set with the setContentView view view, which is created with CreateFlutterView. Let’s look at the implementation.


 @NonNull
private View createFlutterView(a) {
    return this.delegate.onCreateView((LayoutInflater)null, (ViewGroup)null, (Bundle)null);
}
Copy the code

Internal or onCreateView method through FlutterActivityAndFragmentDelegate object to create, so here we focus on the implementation of this class.

2.1 FlutterActivityAndFragmentDelegate

The name of this class is the client for Activity and Fragment of Flutter on Android. It can be assumed that Flutter delegates many activities and fragments related to this class of objects. Let’s focus on the delegate object’s main functions when FlutterActivity is initialized.

  1. onAttach()
  2. onCreateView()

Before we do that, let’s look at its constructor and basic members

final class FlutterActivityAndFragmentDelegate {
    @NonNull
    private FlutterActivityAndFragmentDelegate.Host host;
    @Nullable
    private FlutterEngine flutterEngine;
    @Nullable
    private FlutterSplashView flutterSplashView;
    @Nullable
    private FlutterView flutterView;
    @Nullable
    private PlatformPlugin platformPlugin;
    private boolean isFlutterEngineFromHost;

    FlutterActivityAndFragmentDelegate(@NonNull FlutterActivityAndFragmentDelegate.Host host) {
        this.host = host;
    }

    interface Host extends SplashScreenProvider.FlutterEngineProvider.FlutterEngineConfigurator {}... }Copy the code

FlutterActivity implements FlutterActivityAndFragmentDelegate. The Host interface, the interface object responsible for FlutterActivity and delegate to communicate with each other. There are other members

  1. FlutterEngine represents the rendering engine of Flutter

  2. The flutterSplashView should be the view object for the splash screen page

  3. FlutterView is a flutter view object hosted by FlutterActivity

  4. PlatformPlugin is a platform plug-in object

2.1.1 onAttach
//FlutterActivityAndFragmentDelegate.java
void onAttach(@NonNull Context context) {
    this.ensureAlive();
    if (this.flutterEngine == null) {
        this.setupFlutterEngine();
    }

    this.platformPlugin = this.host.providePlatformPlugin(this.host.getActivity(), this.flutterEngine);
    if (this.host.shouldAttachEngineToActivity()) {
        Log.v("FlutterActivityAndFragmentDelegate"."Attaching FlutterEngine to the Activity that owns this Fragment.");
        this.flutterEngine.getActivityControlSurface().attachToActivity(this.host.getActivity(), this.host.getLifecycle());
    }

    this.host.configureFlutterEngine(this.flutterEngine);
}
Copy the code

In the delegate’s onAttach, the following happens:

  1. Create a Flutter engine using setupFlutterEngine.
  2. Attach the current FlutterActivity to the Flutter engine by attachToActivity
  3. Configure the flutter engine using the configureFlutterEngine
2.1.1.1 create FlutterEngine
@VisibleForTesting
void setupFlutterEngine(a) {...this.flutterEngine = new FlutterEngine(this.host.getContext(), this.host.getFlutterShellArgs().toArray(), false);
            this.isFlutterEngineFromHost = false; . }//FlutterEgine constructor
public FlutterEngine(@NonNull Context context, @NonNull FlutterLoader flutterLoader, @NonNull FlutterJNI flutterJNI, @NonNull PlatformViewsController platformViewsController, @Nullable String[] dartVmArgs, boolean automaticallyRegisterPlugins) {
        this.engineLifecycleListeners = new HashSet();
        this.engineLifecycleListener = new FlutterEngine.EngineLifecycleListener() {
            public void onPreEngineRestart(a) {
                Log.v("FlutterEngine"."onPreEngineRestart()");
                Iterator var1 = FlutterEngine.this.engineLifecycleListeners.iterator();

                while(var1.hasNext()) {
                    FlutterEngine.EngineLifecycleListener lifecycleListener = (FlutterEngine.EngineLifecycleListener)var1.next();
                    lifecycleListener.onPreEngineRestart();
                }

                FlutterEngine.this.platformViewsController.onPreEngineRestart(); }};this.flutterJNI = flutterJNI;
    	// Initialize the engine
        flutterLoader.startInitialization(context.getApplicationContext());
        flutterLoader.ensureInitializationComplete(context, dartVmArgs);
        flutterJNI.addEngineLifecycleListener(this.engineLifecycleListener);
        this.attachToJni();
        this.dartExecutor = new DartExecutor(flutterJNI, context.getAssets());
        this.dartExecutor.onAttachedToJNI();
        // Create a flutter render object
    	this.renderer = new FlutterRenderer(flutterJNI);
        this.accessibilityChannel = new AccessibilityChannel(this.dartExecutor, flutterJNI);
    	// Create different channels
        this.keyEventChannel = new KeyEventChannel(this.dartExecutor);
        this.lifecycleChannel = new LifecycleChannel(this.dartExecutor);
        this.localizationChannel = new LocalizationChannel(this.dartExecutor);
        this.navigationChannel = new NavigationChannel(this.dartExecutor);
        this.platformChannel = new PlatformChannel(this.dartExecutor);
        this.settingsChannel = new SettingsChannel(this.dartExecutor);
        this.systemChannel = new SystemChannel(this.dartExecutor);
        this.textInputChannel = new TextInputChannel(this.dartExecutor);
        this.platformViewsController = platformViewsController;
        this.pluginRegistry = new FlutterEnginePluginRegistry(context.getApplicationContext(), this, flutterLoader);
        if (automaticallyRegisterPlugins) {
            this.registerPlugins(); // Register the plug-in}}Copy the code

This code is responsible for creating the FlutterEngine object FlutterEngine. Some initialization is done by calling startInitialization in the constructor of the FlutterEngine. It was initialized by this method when the FlutterApplication was created and is called again to ensure that it is initialized. Then finish the rest by ensureInitializationComplete initialization, finally create different Channel object for engine and registration by registerPlugins plug-in.

2.1.1.2 ensureInitializationComplete

 public void ensureInitializationComplete(@NonNull Context applicationContext, @Nullable String[] args) {
        if (!this.initialized) {
            if(Looper.myLooper() ! = Looper.getMainLooper()) {throw new IllegalStateException("ensureInitializationComplete must be called on the main thread");
            } else if (this.settings == null) {
                throw new IllegalStateException("ensureInitializationComplete must be called after startInitialization");
            } else {
                try {
                    if (this.resourceExtractor ! =null) {
                        this.resourceExtractor.waitForCompletion();
                    }

                    List<String> shellArgs = new ArrayList();
                    shellArgs.add("--icu-symbol-prefix=_binary_icudtl_dat");
                    ApplicationInfo applicationInfo = this.getApplicationInfo(applicationContext);
                    shellArgs.add("--icu-native-lib-path=" + applicationInfo.nativeLibraryDir + File.separator + "libflutter.so");
                    if(args ! =null) {
                        Collections.addAll(shellArgs, args);
                    }

                    String kernelPath = null;
                    String appStoragePath = PathUtils.getDataDirectory(applicationContext) + File.separator + this.flutterAssetsDir;
                    kernelPath = appStoragePath + File.separator + "kernel_blob.bin";
                    shellArgs.add("--snapshot-asset-path=" + appStoragePath);
                    shellArgs.add("--vm-snapshot-data=" + this.vmSnapshotData);
                    shellArgs.add("--isolate-snapshot-data=" + this.isolateSnapshotData);
                    shellArgs.add("--cache-dir-path=" + PathUtils.getCacheDirectory(applicationContext));
                    if (this.settings.getLogTag() ! =null) {
                        shellArgs.add("--log-tag=" + this.settings.getLogTag());
                    }

                    appStoragePath = PathUtils.getFilesDir(applicationContext);
                    String engineCachesPath = PathUtils.getCacheDirectory(applicationContext);
                    FlutterJNI.nativeInit(applicationContext, (String[])shellArgs.toArray(new String[0]), kernelPath, appStoragePath, engineCachesPath);
                    this.initialized = true;
                } catch (Exception var8) {
                    Log.e("FlutterLoader"."Flutter initialization failed.", var8);
                    throw newRuntimeException(var8); }}}}Copy the code

The engine must be initialized in the Main Thread, followed by preparation of startup parameters for the startup engine and initialization via FlutterJNI’s nativeInit method, which was registered with FlutterMain’s Register method in Section 1.3.2. Let’s move on and look at how it initializes internally.


void FlutterMain::Init(JNIEnv* env, jclass clazz, jobject context, jobjectArray jargs, jstring kernelPath, jstring appStoragePath, jstring engineCachesPath, jlong initTimeMillis) {
  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);

  int64_t init_time_micros = initTimeMillis * 1000;
  settings.engine_start_timestamp =
      std::chrono::microseconds(Dart_TimelineGetMicros() - init_time_micros);

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

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

  flutter::DartCallbackCache::LoadCacheFromDisk(a);if(! flutter::DartVM::IsRunningPrecompiledCode() && kernelPath) {
    // Check to see if the appropriate kernel files are present and configure
    // settings accordingly.
    auto application_kernel_path =
        fml::jni::JavaStringToString(env, kernelPath);

    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)));

  g_flutter_main->SetupObservatoryUriCallback(env);
}
Copy the code

This method saves the command argument args and some resource paths in Settings, and then creates a FlutterMain object from it.

2.1.1.3 attachToJni
//FlutterEngine.java
private void attachToJni(a) {
    Log.v("FlutterEngine"."Attaching to JNI.");
    this.flutterJNI.attachToNative(false); . }//FlutterJni.java
public void attachToNative(boolean isBackgroundView) {
    this.ensureRunningOnMainThread();
    this.ensureNotAttachedToNative();
    this.nativePlatformViewId = this.nativeAttach(this, isBackgroundView);
}

Copy the code

FlutterEngine of Java layer is only a shell. It needs to attach to the engine object of native layer before it can be truly created. Here, the binding with the native engine object is completed through attachToJni method. Before doing this, make sure that the main Thread is running and the object has not been attached. Finally, binding is completed by nativeAttach. This JNI method is registered with PlatformViewAndroid in Section 1.3.3, and its corresponding native method is AttachJNI. Let’s go back to PlatformViewAndroid and look at the concrete implementation of nativeAttach.

//shell/platform/android/platform_view_android_jni_impl.cc
static jlong AttachJNI(JNIEnv* env, jclass clazz, jobject flutterJNI, jboolean is_background_view) {
  fml::jni::JavaObjectWeakGlobalRef java_object(env, flutterJNI);
  std::shared_ptr<PlatformViewAndroidJNI> jni_facade =
      std::make_shared<PlatformViewAndroidJNIImpl>(java_object);
  auto shell_holder = std::make_unique<AndroidShellHolder>(
      FlutterMain::Get().GetSettings(), jni_facade, is_background_view);
  if (shell_holder->IsValid()) {
    return reinterpret_cast<jlong>(shell_holder.release());
  } else {
    return 0; }}Copy the code

In the AttachJNI method it creates an AndroidShellHolder object. Note the three arguments to the AndroidShellHolder constructor:

  1. Get the previously initialized Settings object from FlutterMain
  2. PlatformViewAndroidJNIImpl
  3. Is_background_view defaults to false
2.1.2 create AndroidShellHolder
//shell/platform/android/android_shell_holder.cc
AndroidShellHolder::AndroidShellHolder(
    flutter::Settings settings,
    std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
    bool is_background_view)
    : settings_(std::move(settings)), jni_facade_(jni_facade) {
  static size_t shell_count = 1;
  auto thread_label = std::to_string(shell_count++);
  // Create a thread
  FML_CHECK(pthread_key_create(&thread_destruct_key_, ThreadDestructCallback) ==0); ./ / create ThreadHost
  thread_host_ = {thread_label, ThreadHost::Type::UI | ThreadHost::Type::GPU |
                                      ThreadHost::Type::IO};

  thread_host_.ui_thread->GetTaskRunner() - >PostTask(jni_exit_task);
  if(! is_background_view) { thread_host_.raster_thread->GetTaskRunner() - >PostTask(jni_exit_task);
  }

  fml::WeakPtr<PlatformViewAndroid> weak_platform_view;
  // Create a PlatformView callback that creates a PlatformViewAndroid object
  Shell::CreateCallback<PlatformView> on_create_platform_view =
      [is_background_view, &jni_facade, &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
              jni_facade               // JNI interop
          );
        } else {
          platform_view_android = std::make_unique<PlatformViewAndroid>(
              shell,                   // delegate
              shell.GetTaskRunners(),  // task runners
              jni_facade,              // JNI interop
              shell.GetSettings()
                  .enable_software_rendering  // use software rendering
          );
        }
        weak_platform_view = platform_view_android->GetWeakPtr(a);return platform_view_android;
      };
  // Create a Rasterizer
  Shell::CreateCallback<Rasterizer> on_create_rasterizer = [](Shell& shell) {
    return std::make_unique<Rasterizer>(shell, shell.GetTaskRunners(),
                                        shell.GetIsGpuDisabledSyncSwitch());
  };
	
  // The current thread will be used as the platform thread. Ensure that the
  // message loop is initialized.
  // Initialize the current thread, and initialize the four runners, gup/ UI/IO /platform, while ensuring that the MessageLoop initialization is complete
  fml::MessageLoop::EnsureInitializedForCurrentThread(a); 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(a); . gpu_runner = thread_host_.raster_thread->GetTaskRunner(a); ui_runner = thread_host_.ui_thread->GetTaskRunner(a); io_runner = thread_host_.io_thread->GetTaskRunner(a); .// Create Task runners
  flutter::TaskRunners task_runners(thread_label,     // label
                                      platform_runner,  // platform
                                      gpu_runner,       // raster
                                      ui_runner,        // ui
                                      io_runner         // io
    );
 // Create a Shell object
 shell_ =
        Shell::Create(task_runners,              // task runners
                      GetDefaultPlatformData(),  // window data
                      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_) {
    // The priority of raster and UI threads
    shell_->GetTaskRunners().GetRasterTaskRunner() - >PostTask([] () {if(: :setpriority(PRIO_PROCESS, gettid(), - 5) != 0) {
        if(: :setpriority(PRIO_PROCESS, gettid(), 2 -) != 0) {
          FML_LOG(ERROR) << "Failed to set GPU task runner priority"; }}}); shell_->GetTaskRunners().GetUITaskRunner() - >PostTask([] () {if(: :setpriority(PRIO_PROCESS, gettid(), - 1) != 0) {
        FML_LOG(ERROR) << "Failed to set UI task runner priority"; }}); }}Copy the code

AndroidShellHolder is constructed to accomplish the following tasks:

  1. Create ThreadHost

  2. Create a callback to PlatformView, in this case PlatformViewAndroid

  3. Initialize the current thread and initialize the four runners, gUP/UI/IO /platform, while ensuring that the MessageLoop initialization is complete

  4. Create a task runners

  5. Creating a Shell object

2.1.2.1 ThreadHost
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) {
    raster_thread = std::make_unique<fml::Thread>(name_prefix + ".raster");
  }

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

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

The mask for ThreadHost: : Type: : UI | ThreadHost: : Type: : GPU | ThreadHost: : Type: : IO, so will first create the UI, the GPU, IO this three threads.

2.1.2.2 Creating Shell Objects
// shell/common/shell.cc
std::unique_ptr<Shell> Shell::Create(
    TaskRunners task_runners,
    const PlatformData platform_data,
    Settings settings,
    Shell::CreateCallback<PlatformView> on_create_platform_view,
    Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
  // Initialize the task
  PerformInitializationTasks(settings);
  PersistentCache::SetCacheSkSL(settings.cache_sksl);

  TRACE_EVENT0("flutter"."Shell::Create");
  / / create DartVm
  auto vm = DartVMRef::Create(settings);
  FML_CHECK(vm) << "Must be able to initialize the VM.";

  auto vm_data = vm->GetVMData(a);// Continue Shell creation
  return Shell::Create(std::move(task_runners),        //
                       std::move(platform_data),       //
                       std::move(settings),            //
                       vm_data->GetIsolateSnapshot(),  // isolate snapshot
                       on_create_platform_view,        //
                       on_create_rasterizer,           //
                       std::move(vm)                   //
  );
}
Copy the code

Create a Dart virtual machine DartVm before creating Shell objects

2.1.2.3 Creating Dart VMS
// runtime/dart_vm_lifecycle.cc
DartVMRef DartVMRef::Create(Settings settings, fml::RefPtr
       
         vm_snapshot, fml::RefPtr
        
          isolate_snapshot)
        
        {
  std::scoped_lock lifecycle_lock(gVMMutex); .// If there is already a running VM in the process, grab a strong reference to
  // it.
  // If the process has already run a VM, it returns a strong reference to it
  if (auto vm = gVM.lock()) {
    FML_DLOG(WARNING) << "Attempted to create a VM in a process where one was "
                         "already running. Ignoring arguments for current VM "
                         "create call and reusing the old VM.";
    // There was already a running VM in the process,
    return DartVMRef{std::move(vm)};
  }

  std::scoped_lock dependents_lock(gVMDependentsMutex); .// If there is no VM in the process. Initialize one, hold the weak reference
  // and pass a strong reference to the caller.
    
  auto isolate_name_server = std::make_shared<IsolateNameServer>();
  // Create a VM
  auto vm = DartVM::Create(std::move(settings),          //
                           std::move(vm_snapshot),       //
                           std::move(isolate_snapshot),  //
                           isolate_name_server           //); .return DartVMRef{std::move(vm)};
}
Copy the code

Dart VMS are created in this section

2.1.2.4 Continuing Shell Creation
// shell/common/shell.cc
std::unique_ptr<Shell> Shell::Create(
    TaskRunners task_runners,
    const PlatformData platform_data,
    Settings settings,
    fml::RefPtr<const DartSnapshot> isolate_snapshot,
    const Shell::CreateCallback<PlatformView>& on_create_platform_view,
    const Shell::CreateCallback<Rasterizer>& on_create_rasterizer,
    DartVMRef vm) {
  PerformInitializationTasks(settings);
  PersistentCache::SetCacheSkSL(settings.cache_sksl);

  TRACE_EVENT0("flutter"."Shell::CreateWithSnapshots");

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

  fml::AutoResetWaitableEvent latch;
  std::unique_ptr<Shell> shell;
  fml::TaskRunner::RunNowOrPostTask(
      task_runners.GetPlatformTaskRunner(),
      fml::MakeCopyable([&latch,                                          //
                         vm = std::move(vm),                              //
                         &shell,                                          //
                         task_runners = std::move(task_runners),          //
                         platform_data,                                   //
                         settings,                                        //
                         isolate_snapshot = std::move(isolate_snapshot),  //
                         on_create_platform_view,                         //
                         on_create_rasterizer                             //] ()mutable {
        shell = CreateShellOnPlatformThread(std::move(vm),
                                            std::move(task_runners),      //
                                            platform_data,                //
                                            settings,                     //
                                            std::move(isolate_snapshot),  //
                                            on_create_platform_view,      //
                                            on_create_rasterizer          //
        );
        latch.Signal(a); })); latch.Wait(a);return shell;
}
Copy the code

Create a Shell through CreateShellOnPlatformThread, continue to see its implementation

// shell/common/shell.cc
std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
    DartVMRef vm,
    TaskRunners task_runners,
    const PlatformData platform_data,
    Settings settings,
    fml::RefPtr<const DartSnapshot> isolate_snapshot,
    const Shell::CreateCallback<PlatformView>& on_create_platform_view,
    const Shell::CreateCallback<Rasterizer>& on_create_rasterizer) {...// Create a Shell object
  auto shell =
      std::unique_ptr<Shell>(new Shell(std::move(vm), task_runners, settings));

  // Create the rasterizer on the raster thread.
  // Create a rasterizer in the raster thread
  std::promise<std::unique_ptr<Rasterizer>> rasterizer_promise;
  auto rasterizer_future = rasterizer_promise.get_future(a); std::promise<fml::WeakPtr<SnapshotDelegate>> snapshot_delegate_promise;auto snapshot_delegate_future = snapshot_delegate_promise.get_future(a); fml::TaskRunner::RunNowOrPostTask(
      task_runners.GetRasterTaskRunner(), [&rasterizer_promise,  //
                                           &snapshot_delegate_promise,
                                           on_create_rasterizer,  //
                                           shell = shell.get(a)//] () {TRACE_EVENT0("flutter"."ShellSetupGPUSubsystem");
        std::unique_ptr<Rasterizer> rasterizer(on_create_rasterizer(*shell));
        snapshot_delegate_promise.set_value(rasterizer->GetSnapshotDelegate());
        rasterizer_promise.set_value(std::move(rasterizer));
      });

  // Create the platform view on the platform thread (this thread).
  // Create a platfomeView on the platform thread (current 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.
  // Request VsyncWaiter for platform and the engine will use this object to create animations
  auto vsync_waiter = platform_view->CreateVSyncWaiter(a);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.  
  std::promise<std::unique_ptr<ShellIOManager>> io_manager_promise;
  auto io_manager_future = io_manager_promise.get_future(a); std::promise<fml::WeakPtr<ShellIOManager>> weak_io_manager_promise;auto weak_io_manager_future = weak_io_manager_promise.get_future(a); std::promise<fml::RefPtr<SkiaUnrefQueue>> unref_queue_promise;auto unref_queue_future = unref_queue_promise.get_future(a);auto io_task_runner = shell->GetTaskRunners().GetIOTaskRunner(a);// TODO(gw280): The WeakPtr here asserts that we are derefing it on the
  // same thread as it was created on. We are currently on the IO thread
  // inside this lambda but we need to deref the PlatformView, which was
  // constructed on the platform thread.
  //
  // https://github.com/flutter/flutter/issues/42948
  fml::TaskRunner::RunNowOrPostTask(
      io_task_runner,
      [&io_manager_promise,                                               //
       &weak_io_manager_promise,                                          //
       &unref_queue_promise,                                              //
       platform_view = platform_view->GetWeakPtr(),                       //
       io_task_runner,                                                    //
       is_backgrounded_sync_switch = shell->GetIsGpuDisabledSyncSwitch(a)//] () {TRACE_EVENT0("flutter"."ShellSetupIOSubsystem");
        auto io_manager = std::make_unique<ShellIOManager>(
            platform_view.getUnsafe() - >CreateResourceContext(),
            is_backgrounded_sync_switch, io_task_runner);
        weak_io_manager_promise.set_value(io_manager->GetWeakPtr());
        unref_queue_promise.set_value(io_manager->GetSkiaUnrefQueue());
        io_manager_promise.set_value(std::move(io_manager));
      });

  // Send dispatcher_maker to the engine constructor because shell won't have
  // platform_view set until Shell::Setup is called later.
  auto dispatcher_maker = platform_view->GetDispatcherMaker(a);// Create the engine on the UI thread.
  Create the engine on the UI thread
  std::promise<std::unique_ptr<Engine>> engine_promise;
  auto engine_future = engine_promise.get_future(a); fml::TaskRunner::RunNowOrPostTask(
      shell->GetTaskRunners().GetUITaskRunner(),
      fml::MakeCopyable([&engine_promise,                                 //
                         shell = shell.get(),                             //
                         &dispatcher_maker,                               //
                         &platform_data,                                  //
                         isolate_snapshot = std::move(isolate_snapshot),  //
                         vsync_waiter = std::move(vsync_waiter),          //
                         &weak_io_manager_future,                         //
                         &snapshot_delegate_future,                       //
                         &unref_queue_future                              //] ()mutable {
        TRACE_EVENT0("flutter"."ShellSetupUISubsystem");
        const auto& task_runners = shell->GetTaskRunners(a);// 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_promise.set_value(std::make_unique<Engine>(
            *shell,                         //
            dispatcher_maker,               //
            *shell->GetDartVM(),            //
            std::move(isolate_snapshot),    //
            task_runners,                   //
            platform_data,                  //
            shell->GetSettings(),           //
            std::move(animator),            //
            weak_io_manager_future.get(),   //
            unref_queue_future.get(),       //
            snapshot_delegate_future.get(a)//
            ));
      }));

  if(! shell->Setup(std::move(platform_view),  //
                    engine_future.get(),       //
                    rasterizer_future.get(),   //
                    io_manager_future.get())   //
  ) {
    return nullptr;
  }

  return shell;
}
Copy the code

CreateShellOnPlatformThread method main functions:

  1. The Shell object is created

  2. Create a Rasterizer in the Raster thread

  3. Create a PlatfomeView on a platform thread using the on_create_platform_view callback. In 2.1.2 creating AndroidShellHolder, we know that the PlatformView created is actually PlatformViewAndroid

  4. Request VsyncWaiter for platform, and the engine will create an animation with this object

  5. Create the engine on the UI thread

  6. Create platform_view via Shell

2.1.2.5 Rasterizer Initialization
Rasterizer::Rasterizer(
    Delegate& delegate,
    TaskRunners task_runners,
    std::unique_ptr<flutter::CompositorContext> compositor_context,
    std::shared_ptr<fml::SyncSwitch> is_gpu_disabled_sync_switch)
    : delegate_(delegate),
      task_runners_(std::move(task_runners)),
      compositor_context_(std::move(compositor_context)),
      user_override_resource_cache_bytes_(false),
      weak_factory_(this),
      is_gpu_disabled_sync_switch_(is_gpu_disabled_sync_switch) {
  FML_DCHECK(compositor_context_);
}
Copy the code
2.1.2.6 PlatformViewAndroid create
// shell/platform/android/platform_view_android.cc
PlatformViewAndroid::PlatformViewAndroid(
    PlatformView::Delegate& delegate,
    flutter::TaskRunners task_runners,
    std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
    bool use_software_rendering)
    : PlatformView(delegate, std::move(task_runners)),
      jni_facade_(jni_facade),
      platform_view_android_delegate_(jni_facade) {
  std::shared_ptr<AndroidContext> android_context;
  if (use_software_rendering) {
    android_context =
        std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
  } else {
#if SHELL_ENABLE_VULKAN
    android_context =
        std::make_shared<AndroidContext>(AndroidRenderingAPI::kVulkan);
#else   // SHELL_ENABLE_VULKAN
    android_context = std::make_shared<AndroidContextGL>(
        AndroidRenderingAPI::kOpenGLES,
        fml::MakeRefCounted<AndroidEnvironmentGL>());
#endif  // SHELL_ENABLE_VULKAN
  }
  FML_CHECK(android_context && android_context->IsValid()) < <"Could not create an Android context.";

  android_surface_ = SurfaceFactory(std::move(android_context), jni_facade);
  FML_CHECK(android_surface_ && android_surface_->IsValid()) < <"Could not create an OpenGL, Vulkan or Software surface to setup "
         "rendering.";
}
Copy the code

AndroidSurface has three rendering methods: software rendering, VULKAN rendering, and GLES rendering. It is created by SurfaceFactor.

2.1.2.7 create Engine
Engine::Engine(Delegate& delegate,
               const PointerDataDispatcherMaker& dispatcher_maker,
               DartVM& vm,
               fml::RefPtr<const DartSnapshot> isolate_snapshot,
               TaskRunners task_runners,
               const PlatformData platform_data,
               Settings settings,
               std::unique_ptr<Animator> animator,
               fml::WeakPtr<IOManager> io_manager,
               fml::RefPtr<SkiaUnrefQueue> unref_queue,
               fml::WeakPtr<SnapshotDelegate> snapshot_delegate)
    : delegate_(delegate),
      settings_(std::move(settings)),
      animator_(std::move(animator)),
      activity_running_(true),
      have_surface_(false),
      image_decoder_(task_runners,
                     vm.GetConcurrentWorkerTaskRunner(),
                     io_manager),
      task_runners_(std::move(task_runners)),
      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<RuntimeController>(
      *this.// runtime delegate
      &vm,                          // VM
      std::move(isolate_snapshot),  // isolate snapshot
      task_runners_,                // task runners
      std::move(snapshot_delegate),
      std::move(io_manager),                 // io manager
      std::move(unref_queue),                // Skia unref queue
      image_decoder_.GetWeakPtr(),           // image decoder
      settings_.advisory_script_uri,         // advisory script uri
      settings_.advisory_script_entrypoint,  // advisory script entrypoint
      settings_.idle_notification_callback,  // idle notification callback
      platform_data,                         // platform data
      settings_.isolate_create_callback,     // isolate create callback
      settings_.isolate_shutdown_callback,   // isolate shutdown callback
      settings_.persistent_isolate_data      // persistent isolate data
  );

  pointer_data_dispatcher_ = dispatcher_maker(*this);
}
Copy the code

The RuntimeController is created in the Engine constructor, which should be called the RuntimeController by name.

2.1.2.8 Shell: : Setup
bool Shell::Setup(std::unique_ptr
       
         platform_view, std::unique_ptr
        
          engine, std::unique_ptr
         
           rasterizer, std::unique_ptr
          
            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);

  // The weak ptr must be generated in the platform thread which owns the unique
  // ptr.
  weak_engine_ = engine_->GetWeakPtr(a); weak_rasterizer_ = rasterizer_->GetWeakPtr(a); weak_platform_view_ = platform_view_->GetWeakPtr(a);// Setup the time-consuming default font manager right after engine created.
  fml::TaskRunner::RunNowOrPostTask(task_runners_.GetUITaskRunner(),
                                    [engine = weak_engine_] {
                                      if (engine) {
                                        engine->SetupDefaultFontManager();
                                      }
                                    });

  is_setup_ = true;

  vm_->GetServiceProtocol() - >AddHandler(this.GetServiceProtocolDescription());

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

  PersistentCache::GetCacheForProcess() - >SetIsDumpingSkp(
      settings_.dump_skp_on_shader_compilation);

  if (settings_.purge_persistent_cache) {
    PersistentCache::GetCacheForProcess() - >Purge(a); }// TODO(gw280): The WeakPtr here asserts that we are derefing it on the
  // same thread as it was created on. Shell is constructed on the platform
  // thread but we need to call into the Engine on the UI thread, so we need
  // to use getUnsafe() here to avoid failing the assertion.
  //
  // https://github.com/flutter/flutter/issues/42947
  display_refresh_rate_ = weak_engine_.getUnsafe() - >GetDisplayRefreshRate(a);return true;
}
Copy the code
2.1.3 onCreateView

In FlutterActivity’s onCreate, the Delegate onAttach method completes the creation of DartVm, three threads (gUP, UI, IO), and the creation of the Engine object. It then creates a view object for the FlutterActivity with CreateFlutterView, which eventually calls the delegate onCreateView to do so.

View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.v("FlutterActivityAndFragmentDelegate"."Creating FlutterView.");
        this.ensureAlive();
    	Create a FLUTTER view object
        if (this.host.getRenderMode() == RenderMode.surface) {
            FlutterSurfaceView flutterSurfaceView = new FlutterSurfaceView(this.host.getActivity(), this.host.getTransparencyMode() == TransparencyMode.transparent);
            this.host.onFlutterSurfaceViewCreated(flutterSurfaceView);
            this.flutterView = new FlutterView(this.host.getActivity(), flutterSurfaceView);
        } else {
            FlutterTextureView flutterTextureView = new FlutterTextureView(this.host.getActivity());
            this.host.onFlutterTextureViewCreated(flutterTextureView);
            this.flutterView = new FlutterView(this.host.getActivity(), flutterTextureView);
        }

        this.flutterView.addOnFirstFrameRenderedListener(this.flutterUiDisplayListener);
        this.flutterSplashView = new FlutterSplashView(this.host.getContext());
        if (VERSION.SDK_INT >= 17) {
            this.flutterSplashView.setId(View.generateViewId());
        } else {
            this.flutterSplashView.setId(486947586);
        }

        this.flutterSplashView.displayFlutterViewWithSplash(this.flutterView, this.host.provideSplashScreen());
        Log.v("FlutterActivityAndFragmentDelegate"."Attaching FlutterEngine to FlutterView.");
    	Attach the Flutter view to the FlutterEngine
        this.flutterView.attachToFlutterEngine(this.flutterEngine);
        return this.flutterSplashView;
}
Copy the code

OnCreateView is responsible for creating view objects for FlutterActivity. First, it decides which view to create based on the RenderMode. If rendermode. surface is used to create the FlutterView, which is actually the SurfaceView implementation inside. Otherwise build via FlutterTextureView and internally implement via TextureView.

Rendering mode is determined by default in FlutterActivity using the following criteria:

public RenderMode getRenderMode(a) {
   return this.getBackgroundMode() == BackgroundMode.opaque ? RenderMode.surface : RenderMode.texture;
}
Copy the code

If the background is opaque, the RenderMode is rendermode.surface. Then create a FlutterSplashView(actually FrameLayout) and return the splash View to the Host Activity, since the splash page is the first View of the page. The subsequent content is rendered to the flutterView by the FlutterEngine. This is attached to the engine by attachToFlutterEngine. Let’s first look at the constructor of the FlutterView

// FlutterView.java
public FlutterView(@NonNull Context context, @NonNull FlutterView.RenderMode renderMode) {
        super(context, (AttributeSet)null);
        this.flutterUiDisplayListeners = new HashSet();
        this.flutterEngineAttachmentListeners = new HashSet();
        this.viewportMetrics = new ViewportMetrics();
        this.onAccessibilityChangeListener = new NamelessClass_2();
        this.flutterUiDisplayListener = new NamelessClass_1();
        if (renderMode == FlutterView.RenderMode.surface) {
            this.flutterSurfaceView = new FlutterSurfaceView(context);
            this.renderSurface = this.flutterSurfaceView;
        } else {
            this.flutterTextureView = new FlutterTextureView(context);
            this.renderSurface = this.flutterTextureView;
        }

        this.init();
}
Copy the code

The FlutterView constructor initializes the RenderSurface with the FlutterSurfaceView and FlutterTextView because they both implement the RenderSurface interface internally.

//RenderSurface.java
public interface RenderSurface {
    @Nullable
    FlutterRenderer getAttachedRenderer(a);
    void attachToRenderer(@NonNull FlutterRenderer var1);
    void detachFromRenderer(a);
}
Copy the code
2.1.3.1 attachToFlutterEngine

Next look at the implementation inside attachToFlutterEngine

//FlutterView.class
public void attachToFlutterEngine(@NonNull FlutterEngine flutterEngine) {...this.flutterEngine = flutterEngine;
    	// Get the FlutterRenderer object from the engine
        FlutterRenderer flutterRenderer = this.flutterEngine.getRenderer();
        this.isFlutterUiDisplayed = flutterRenderer.isDisplayingFlutterUi();
    	// Bind the view to FlutterRenderer
        this.renderSurface.attachToRenderer(flutterRenderer);
        flutterRenderer.addIsDisplayingFlutterUiListener(this.flutterUiDisplayListener);
        this.textInputPlugin = new TextInputPlugin(this.this.flutterEngine.getDartExecutor(), this.flutterEngine.getPlatformViewsController());
        this.androidKeyProcessor = new AndroidKeyProcessor(this.flutterEngine.getKeyEventChannel(), this.textInputPlugin);
        this.androidTouchProcessor = new AndroidTouchProcessor(this.flutterEngine.getRenderer());
        this.accessibilityBridge = new AccessibilityBridge(this, flutterEngine.getAccessibilityChannel(), (AccessibilityManager)this.getContext().getSystemService("accessibility"), this.getContext().getContentResolver(), this.flutterEngine.getPlatformViewsController());
        this.accessibilityBridge.setOnAccessibilityChangeListener(this.onAccessibilityChangeListener);
        this.resetWillNotDraw(this.accessibilityBridge.isAccessibilityEnabled(), this.accessibilityBridge.isTouchExplorationEnabled());
        this.flutterEngine.getPlatformViewsController().attachAccessibilityBridge(this.accessibilityBridge);
        this.textInputPlugin.getInputMethodManager().restartInput(this);
        this.sendUserSettingsToFlutter();
        this.sendLocalesToFlutter(this.getResources().getConfiguration());
        this.sendViewportMetricsToFlutter();
    	// Bind the view to the engine's PlatformViewsController
        flutterEngine.getPlatformViewsController().attachToView(this); . }Copy the code

In attachToFlutterEngine, a FlutterRenderer is first obtained by The flutterEngine, which should be used to render the view, and then the renderSurface of the FlutterView is attached to it. Finally, the engine will get a PlatFormViewController and attach it to the current view.

2.1.3.2 attachToRenderer
// FlutterSurfaceView.java
public void attachToRenderer(@NonNull FlutterRenderer flutterRenderer) {...this.flutterRenderer = flutterRenderer;
        this.isAttachedToFlutterRenderer = true;
        this.flutterRenderer.addIsDisplayingFlutterUiListener(this.flutterUiDisplayListener);
        if (this.isSurfaceAvailableForRendering) {
            Log.v("FlutterSurfaceView"."Surface is available for rendering. Connecting FlutterRenderer to Android surface.");
            this.connectSurfaceToRenderer(); }}private void connectSurfaceToRenderer(a) {
        if (this.flutterRenderer ! =null && this.getHolder() ! =null) {
            this.flutterRenderer.startRenderingToSurface(this.getHolder().getSurface());
        } else {
            throw new IllegalStateException("connectSurfaceToRenderer() should only be called when flutterRenderer and getHolder() are non-null."); }}//FlutterRenderer.java
public void startRenderingToSurface(@NonNull Surface surface) {
    if (this.surface ! =null) {
        this.stopRenderingToSurface();
    }

    this.surface = surface;
    this.flutterJNI.onSurfaceCreated(surface);
}

@UiThread
public void onSurfaceCreated(@NonNull Surface surface) {
    this.ensureRunningOnMainThread();
    this.ensureAttachedToNative();
    this.nativeSurfaceCreated(this.nativePlatformViewId, surface);
}
Copy the code

Here we can look at the implementation of attachToRenderer in FlutterSurfaceView. FlutterTextView is left for readers to analyze by themselves. The method first adds a flutter UI listener. The FlutterRenderer is then connected via connectSurfaceToRenderer(). FlutterRender calls startRenderingToSurface and passes it the drawing Surface object of the current FlutterSurfaceView, Surface, Finally through flutterJNI. The onSurfaceCreated calls to jni nativeSurfaceCreated, the jni methods registered in 1.3.3 registration section PlatformViewAndroid RegisterApi Its corresponding native method is SurfaceCreated.

2.1.3.3 SurfaceCreated
//shell/platform/android/platform_view_android_jni_impl.cc
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));
}

//shell/platform/android/platform_view_android.cc
void PlatformViewAndroid::NotifyCreated( fml::RefPtr
       
         native_window)
        {
  if (android_surface_) {
    InstallFirstFrameCallback(a); fml::AutoResetWaitableEvent latch; fml::TaskRunner::RunNowOrPostTask(
        task_runners_.GetRasterTaskRunner(),
        [&latch, surface = android_surface_.get(),
         native_window = std::move(native_window)]() {
          surface->SetNativeWindow(native_window);
          latch.Signal(a); }); latch.Wait(a); } PlatformView::NotifyCreated(a); }Copy the code

You can see that ANativeWindow_fromSurface creates an ANativeWindow from the surface. This ANativeWindow must be familiar to anyone who has read Android source code. It represents the local window, which is the bridge between GPU rendering and screen. And then ANDROID_SHELL_HOLDER gets the PlatformView, so here’s the PlatformViewAndroid object, which tells you to create the window.

Three, the engine start process

In the onCreate FlutterActivity, through the delegate class FlutterActivityAndFragmentDelegate completed preparations to Flutter engine initialization, and views. The next step is to start the engine, which is done in onStart.

// FlutterActivityAndFragmentDelegate.java
void onStart(a) {
    Log.v("FlutterActivityAndFragmentDelegate"."onStart()");
    this.ensureAlive();
    this.doInitialFlutterViewRun();
}

private void doInitialFlutterViewRun(a) {
        if (this.host.getCachedEngineId() == null) {
            if (!this.flutterEngine.getDartExecutor().isExecutingDart()) {
                if (this.host.getInitialRoute() ! =null) {
                    this.flutterEngine.getNavigationChannel().setInitialRoute(this.host.getInitialRoute());
                }

                DartEntrypoint entrypoint = new DartEntrypoint(this.host.getAppBundlePath(), this.host.getDartEntrypointFunctionName());
                this.flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint); }}}public String getDartEntrypointFunctionName(a) {
     try {
         ActivityInfo activityInfo = this.getPackageManager().getActivityInfo(this.getComponentName(), 128); Bundle metadata = activityInfo.metaData; String desiredDartEntrypoint = metadata ! =null ? metadata.getString("io.flutter.Entrypoint") : null;
         returndesiredDartEntrypoint ! =null ? desiredDartEntrypoint : "main";
     } catch (NameNotFoundException var4) {
         return "main"; }}Copy the code

Call doInitialFlutterViewRun in the onStart method to start rendering FlutterView. Inside the method, execute via executeDartEntrypoint, which passes it a DartEntryPoint, Dart access point as the name implies. This object by getAppBundlePath and getDartEntrypointFunctionName to create two methods to get to the variables. GetAppBundlePath access to the resource path Dart files, getDartEntrypointFunctionName to is Lord of the Dart files operation method, the default name of the method is the main, the main method of the Dart.

3.1 executeDartEntrypoint

//DartExecutor.java
public void executeDartEntrypoint(@NonNull DartExecutor.DartEntrypoint dartEntrypoint) {
        if (this.isApplicationRunning) {
            Log.w("DartExecutor"."Attempted to run a DartExecutor that is already running.");
        } else {
            Log.v("DartExecutor"."Executing Dart entrypoint: " + dartEntrypoint);
            this.flutterJNI.runBundleAndSnapshotFromLibrary(dartEntrypoint.pathToBundle, dartEntrypoint.dartEntrypointFunctionName, (String)null.this.assetManager);
            this.isApplicationRunning = true; }}//FlutterJNI.java
@UiThread
  public void runBundleAndSnapshotFromLibrary(
      @NonNull String bundlePath,
      @Nullable String entrypointFunctionName,
      @Nullable String pathToEntrypointFunction,
      @NonNull AssetManager assetManager) { ensureRunningOnMainThread(); ensureAttachedToNative(); nativeRunBundleAndSnapshotFromLibrary( nativePlatformViewId, bundlePath, entrypointFunctionName, pathToEntrypointFunction, assetManager); }Copy the code

Internal call FlutterJNI runBundleAndSnapshotFromLibrary method, this method internal call nativeRunBundleAndSnapshotFromLibrary jni method, This JNI method is also registered in the RegisterApi method of 1.3.3 Registering PlatformViewAndroid.

3.2 nativeRunBundleAndSnapshotFromLibrary

//shell/platform/android/platform_view_android_jni_impl.cc
static void RunBundleAndSnapshotFromLibrary(JNIEnv* env, jobject jcaller, jlong shell_holder, jstring jBundlePath, jstring jEntrypoint, jstring jLibraryUrl, jobject jAssetManager) {
  auto asset_manager = std::make_shared<flutter::AssetManager>();

  asset_manager->PushBack(std::make_unique<flutter::APKAssetProvider>(
      env,                                             // jni environment
      jAssetManager,                                   // asset manager
      fml::jni::JavaStringToString(env, jBundlePath))  // apk asset dir
  );

  std::unique_ptr<IsolateConfiguration> isolate_configuration;
  if (flutter::DartVM::IsRunningPrecompiledCode()) {
    isolate_configuration = IsolateConfiguration::CreateForAppSnapshot(a); }else {
    std::unique_ptr<fml::Mapping> kernel_blob =
        fml::FileMapping::CreateReadOnly(
            ANDROID_SHELL_HOLDER->GetSettings().application_kernel_asset);
    if(! kernel_blob) {FML_DLOG(ERROR) << "Unable to load the kernel blob asset.";
      return;
    }
    isolate_configuration =
        IsolateConfiguration::CreateForKernel(std::move(kernel_blob));
  }
  // Initialize RunConfiguration
  RunConfiguration config(std::move(isolate_configuration), std::move(asset_manager));

  {
    auto entrypoint = fml::jni::JavaStringToString(env, jEntrypoint);
    auto libraryUrl = fml::jni::JavaStringToString(env, jLibraryUrl);

    if ((entrypoint.size(a) >0) && (libraryUrl.size(a) >0)) {
      config.SetEntrypointAndLibrary(std::move(entrypoint),
                                     std::move(libraryUrl));
    } else if (entrypoint.size(a) >0) {
      config.SetEntrypoint(std::move(entrypoint));
    }
  }

  ANDROID_SHELL_HOLDER->Launch(std::move(config));
}
Copy the code

This method creates a RunConfiguration object for engine startup and is further processed by the Launch of ANDROID_SHELL_HOLDER.

//shell/platform/android/android_shell_holder.cc
void AndroidShellHolder::Launch(RunConfiguration config) {
  if (!IsValid()) {
    return;
  }
  shell_->RunEngine(std::move(config));
}
Copy the code

Here you can see that the engine is started by Shell

3.3 RunEngine

// shell/common/shell.cc
void Shell::RunEngine(
    RunConfiguration run_configuration,
    const std::function<void(Engine::RunStatus)>& result_callback) {... fml::TaskRunner::RunNowOrPostTask(
      task_runners_.GetUITaskRunner(),
      fml::MakeCopyable(
          [run_configuration = std::move(run_configuration),
           weak_engine = weak_engine_, result]() mutable {
            if(! weak_engine) {FML_LOG(ERROR)
                  << "Could not launch engine with configuration - no engine.";
              result(Engine::RunStatus::Failure);
              return;
            }
            // Start the engine
            auto run_result = weak_engine->Run(std::move(run_configuration));
            if (run_result == flutter::Engine::RunStatus::Failure) {
              FML_LOG(ERROR) << "Could not launch engine with configuration.";
            }
            result(run_result);
          }));
}
Copy the code

Further processing is done within RunEngine through Engine’s Run method

// shell/common/engine.cc
Engine::RunStatus Engine::Run(RunConfiguration configuration) {
  
  // Obtain the configured EntryPoint
  last_entry_point_ = configuration.GetEntrypoint(a); last_entry_point_library_ = configuration.GetEntrypointLibrary(a);// Prepare and load the ISOLATE
  auto isolate_launch_status =
      PrepareAndLaunchIsolate(std::move(configuration)); . }Copy the code

3.4 PrepareAndLaunchIsolate

//shell/common/engine.cc
Engine::RunStatus Engine::PrepareAndLaunchIsolate( RunConfiguration configuration) {
  auto isolate_configuration = configuration.TakeIsolateConfiguration(a); std::shared_ptr<DartIsolate> isolate = runtime_controller_->GetRootIsolate().lock(a); ./ / ready to isolate
  if(! isolate_configuration->PrepareIsolate(*isolate)) {
    FML_LOG(ERROR) << "Could not prepare to run the isolate.";
    returnRunStatus::Failure; }...// Start with DartIsolate's run method
  if(! isolate->Run(configuration.GetEntrypoint(),
                      settings_.dart_entrypoint_args)) {
      FML_LOG(ERROR) << "Could not run the isolate.";
      returnRunStatus::Failure; }...return RunStatus::Success;
}
Copy the code
// runtime/dart_isolate.cc
[[nodiscard]] bool DartIsolate::Run(const std::string& entrypoint_name,
                                    const std::vector<std::string>& args,
                                    const fml::closure& on_run) {
  TRACE_EVENT0("flutter"."DartIsolate::Run");
  if(phase_ ! = Phase::Ready) {return false;
  }

  tonic::DartState::Scope scope(this);

  auto user_entrypoint_function =
      Dart_GetField(Dart_RootLibrary(), tonic::ToDart(entrypoint_name.c_str()));

  auto entrypoint_args = tonic::ToDart(args);
  // Call main
  if (!InvokeMainEntrypoint(user_entrypoint_function, entrypoint_args)) {
    return false;
  }

  phase_ = Phase::Running;

  if (on_run) {
    on_run(a); }return true;
}
Copy the code

Here entrypoint_name is the main method name “main”. This method gets the entry function corresponding to the name of the main method, that is, the main method. The main method is then called through InvokeMainEntrypoint.

3.5 Calling the main method

// runtime/dart_isolate.cc
[[nodiscard]] static bool InvokeMainEntrypoint( Dart_Handle user_entrypoint_function, Dart_Handle args) {... Dart_Handle start_main_isolate_function = tonic::DartInvokeField(Dart_LookupLibrary(tonic::ToDart("dart:isolate")),
                             "_getStartMainIsolateFunction"{}); .if (tonic::LogIfError(tonic::DartInvokeField(
          Dart_LookupLibrary(tonic::ToDart("dart:ui")), "_runMainZoned",
          {start_main_isolate_function, user_entrypoint_function, args}))) {
    FML_LOG(ERROR) << "Could not invoke the main entrypoint.";
    return false;
  }    
  return true;
}
Copy the code

The main method is finally started using the _runMainZoned() method of the Dart VM.

//lib/ui/hooks.dart
@pragma('vm:entry-point')
// ignore: unused_element
void _runMainZoned(Function startMainIsolateFunction,
                   Function userMainFunction,
                   List<String> args) {
  startMainIsolateFunction((){
    runZonedGuarded<void> (() {if (userMainFunction is _BinaryFunction) {
        // This seems to be undocumented but supported by the command line VM.
        // Let's do the same in case old entry-points are ported to Flutter.
        (userMainFunction as dynamic)(args, ' ');
      } else if (userMainFunction is _UnaryFunction) {
        (userMainFunction as dynamic)(args);
      } else{ userMainFunction(); }},Object error, StackTrace stackTrace) {
      _reportUnhandledException(error.toString(), stackTrace.toString());
    });
  }, null);
}
Copy the code

Here userMainFunction is equal to the main() method in the main.dart file.