Setup default font manager after engine created, to improve startup performance (#18225)

diff --git a/lib/ui/text/font_collection.cc b/lib/ui/text/font_collection.cc
index 8d10708..c59dac7 100644
--- a/lib/ui/text/font_collection.cc
+++ b/lib/ui/text/font_collection.cc
@@ -47,8 +47,6 @@
 
 FontCollection::FontCollection()
     : collection_(std::make_shared<txt::FontCollection>()) {
-  collection_->SetupDefaultFontManager();
-
   dynamic_font_manager_ = sk_make_sp<txt::DynamicFontManager>();
   collection_->SetDynamicFontManager(dynamic_font_manager_);
 }
@@ -68,6 +66,10 @@
   return collection_;
 }
 
+void FontCollection::SetupDefaultFontManager() {
+  collection_->SetupDefaultFontManager();
+}
+
 void FontCollection::RegisterFonts(
     std::shared_ptr<AssetManager> asset_manager) {
   std::unique_ptr<fml::Mapping> manifest_mapping =
diff --git a/lib/ui/text/font_collection.h b/lib/ui/text/font_collection.h
index 4e19e2a..48e0e1e 100644
--- a/lib/ui/text/font_collection.h
+++ b/lib/ui/text/font_collection.h
@@ -29,6 +29,8 @@
 
   std::shared_ptr<txt::FontCollection> GetFontCollection() const;
 
+  void SetupDefaultFontManager();
+
   void RegisterFonts(std::shared_ptr<AssetManager> asset_manager);
 
   void RegisterTestFonts();
diff --git a/shell/common/engine.cc b/shell/common/engine.cc
index 4703411..9f03c92 100644
--- a/shell/common/engine.cc
+++ b/shell/common/engine.cc
@@ -90,6 +90,11 @@
   return weak_factory_.GetWeakPtr();
 }
 
+void Engine::SetupDefaultFontManager() {
+  TRACE_EVENT0("flutter", "Engine::SetupDefaultFontManager");
+  font_collection_.SetupDefaultFontManager();
+}
+
 bool Engine::UpdateAssetManager(
     std::shared_ptr<AssetManager> new_asset_manager) {
   if (asset_manager_ == new_asset_manager) {
diff --git a/shell/common/engine.h b/shell/common/engine.h
index 0f5f071..5f970b3 100644
--- a/shell/common/engine.h
+++ b/shell/common/engine.h
@@ -364,6 +364,11 @@
   [[nodiscard]] bool Restart(RunConfiguration configuration);
 
   //----------------------------------------------------------------------------
+  /// @brief      Setup default font manager according to specific platform.
+  ///
+  void SetupDefaultFontManager();
+
+  //----------------------------------------------------------------------------
   /// @brief      Updates the asset manager referenced by the root isolate of a
   ///             Flutter application. This happens implicitly in the call to
   ///             `Engine::Run` and `Engine::Restart` as the asset manager is
diff --git a/shell/common/shell.cc b/shell/common/shell.cc
index fd5a581..99236e0 100644
--- a/shell/common/shell.cc
+++ b/shell/common/shell.cc
@@ -542,6 +542,14 @@
   weak_rasterizer_ = rasterizer_->GetWeakPtr();
   weak_platform_view_ = platform_view_->GetWeakPtr();
 
+  // 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());
diff --git a/shell/platform/android/flutter_main.cc b/shell/platform/android/flutter_main.cc
index cb2d516..1493bf4 100644
--- a/shell/platform/android/flutter_main.cc
+++ b/shell/platform/android/flutter_main.cc
@@ -21,6 +21,7 @@
 #include "flutter/shell/common/shell.h"
 #include "flutter/shell/common/switches.h"
 #include "third_party/dart/runtime/include/dart_tools_api.h"
+#include "third_party/skia/include/core/SkFontMgr.h"
 
 namespace flutter {
 
@@ -155,6 +156,11 @@
       });
 }
 
+static void PrefetchDefaultFontManager(JNIEnv* env, jclass jcaller) {
+  // Initialize a singleton owned by Skia.
+  SkFontMgr::RefDefault();
+}
+
 bool FlutterMain::Register(JNIEnv* env) {
   static const JNINativeMethod methods[] = {
       {
@@ -163,6 +169,11 @@
                        "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");
diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java
index 6f55fce..b0d5ad9 100644
--- a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java
+++ b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java
@@ -106,6 +106,13 @@
       @NonNull String engineCachesPath,
       long initTimeMillis);
 
+  /**
+   * Prefetch the default font manager provided by SkFontMgr::RefDefault() which is a process-wide
+   * singleton owned by Skia. Note that, the first call to SkFontMgr::RefDefault() will take
+   * noticeable time, but later calls will return a reference to the preexisting font manager.
+   */
+  public static native void nativePrefetchDefaultFontManager();
+
   // TODO(mattcarroll): add javadocs
   @UiThread
   public native boolean nativeGetIsSoftwareRenderingEnabled();
diff --git a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java
index bd50695..c57d8c8 100644
--- a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java
+++ b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java
@@ -144,6 +144,17 @@
 
             System.loadLibrary("flutter");
 
+            // Prefetch the default font manager as soon as possible on a background thread.
+            // It helps to reduce time cost of engine setup that blocks the platform thread.
+            Executors.newSingleThreadExecutor()
+                .execute(
+                    new Runnable() {
+                      @Override
+                      public void run() {
+                        FlutterJNI.nativePrefetchDefaultFontManager();
+                      }
+                    });
+
             if (resourceExtractor != null) {
               resourceExtractor.waitForCompletion();
             }