Flutter啟動流程簡析

juexingzhe發表於2019-04-26

Flutter啟動流程簡析

今天基於Android分析下Flutter的啟動流程,首先看下官網提供的框架圖,最下面一層Embedder是特定的平臺實現,Android平臺程式碼在engine/shell/platform/android下,其中有java的嫁接層在engine/shell/platform/android/io/flutter下面。Embedder層是Flutter啟動的關鍵,在應用啟動後通過該層初始化Flutter Engine,在Engine中會建立DartVM,在DartVM中執行dart編寫的入口方法main方法,這樣Flutter模組就啟動成功。

1.Android平臺程式碼分析

這部分程式碼是Embedder層的,在engine/shell/platform/android/io/flutter下面。

首先看到FlutterApplication中的onCreate

    @CallSuper
    public void onCreate() {
        super.onCreate();
        FlutterMain.startInitialization(this);
    }
複製程式碼

接著到FlutterMain中:

    public static void startInitialization(Context applicationContext, FlutterMain.Settings settings) {
        if (Looper.myLooper() != Looper.getMainLooper()) {
            throw new IllegalStateException("startInitialization must be called on the main thread");
        } else if (sSettings == null) {
            sSettings = settings;
            long initStartTimestampMillis = SystemClock.uptimeMillis();
            initConfig(applicationContext);
            initAot(applicationContext);
            initResources(applicationContext);
            System.loadLibrary("flutter");
            long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis;
            nativeRecordStartTimestamp(initTimeMillis);
        }
    }
複製程式碼

在這裡會進行配置資訊初始化,初始化AOT模式或者JIT模式變數,資原始檔初始化,主要是將asset目錄下的flutter相關資源copy到私有目錄下,看一個手機上私有目錄下的截圖

Flutter啟動流程簡析

最後呼叫JNI方法nativeRecordStartTimestamp記錄到C++層。

FlutterApplication執行完會執行MainActivity中的onCreate,主要工作會在父類FlutterActivity中,然後委託給FlutterActivityDelegate:

// FlutterActivity    
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.eventDelegate.onCreate(savedInstanceState);
}

// FlutterActivityDelegate
    @Override
public void onCreate(Bundle savedInstanceState) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        Window window = activity.getWindow();
        window.addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        window.setStatusBarColor(0x40000000);
        window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI);
    }

    String[] args = getArgsFromIntent(activity.getIntent());
    FlutterMain.ensureInitializationComplete(activity.getApplicationContext(), args);

    flutterView = viewFactory.createFlutterView(activity);
    if (flutterView == null) {
        FlutterNativeView nativeView = viewFactory.createFlutterNativeView();
        flutterView = new FlutterView(activity, null, nativeView);
        flutterView.setLayoutParams(matchParent);
        activity.setContentView(flutterView);
        launchView = createLaunchView();
        if (launchView != null) {
            addLaunchView();
        }
    }

    if (loadIntent(activity.getIntent())) {
        return;
    }

    String appBundlePath = FlutterMain.findAppBundlePath(activity.getApplicationContext());
    if (appBundlePath != null) {
        runBundle(appBundlePath);
    }
}

複製程式碼

可以看到有個setContentView,就是在這裡設定內容檢視,總結下FlutterActivityDelegate做的事:

1.根據系統版本設定狀態列樣式

2.獲取Intent

3.FlutterMain.ensureInitializationComplete

4.create FlutterNativeView

5.create FlutterView

6.設定activity的內容檢視

7.執行appBundlePath

前面2步沒什麼說的,從第3步開始看。

2.FlutterMain

public static void ensureInitializationComplete(Context applicationContext, String[] args) {
        if (Looper.myLooper() != Looper.getMainLooper()) {
            throw new IllegalStateException("ensureInitializationComplete must be called on the main thread");
        } else if (sSettings == null) {
            throw new IllegalStateException("ensureInitializationComplete must be called after startInitialization");
        } else if (!sInitialized) {
            try {
                sResourceExtractor.waitForCompletion();
                List<String> shellArgs = new ArrayList();
                shellArgs.add("--icu-symbol-prefix=_binary_icudtl_dat");
                if (args != null) {
                    Collections.addAll(shellArgs, args);
                }

                if (sIsPrecompiledAsSharedLibrary) {
                    shellArgs.add("--aot-shared-library-path=" + new File(PathUtils.getDataDirectory(applicationContext), sAotSharedLibraryPath));
                } else {
                    if (sIsPrecompiledAsBlobs) {
                        shellArgs.add("--aot-snapshot-path=" + PathUtils.getDataDirectory(applicationContext));
                    } else {
                        shellArgs.add("--cache-dir-path=" + PathUtils.getCacheDirectory(applicationContext));
                        shellArgs.add("--aot-snapshot-path=" + PathUtils.getDataDirectory(applicationContext) + "/" + sFlutterAssetsDir);
                    }

                    shellArgs.add("--vm-snapshot-data=" + sAotVmSnapshotData);
                    shellArgs.add("--vm-snapshot-instr=" + sAotVmSnapshotInstr);
                    shellArgs.add("--isolate-snapshot-data=" + sAotIsolateSnapshotData);
                    shellArgs.add("--isolate-snapshot-instr=" + sAotIsolateSnapshotInstr);
                }

                if (sSettings.getLogTag() != null) {
                    shellArgs.add("--log-tag=" + sSettings.getLogTag());
                }

                String appBundlePath = findAppBundlePath(applicationContext);
                String appStoragePath = PathUtils.getFilesDir(applicationContext);
                String engineCachesPath = PathUtils.getCacheDirectory(applicationContext);
                nativeInit(applicationContext, (String[])shellArgs.toArray(new String[0]), appBundlePath, appStoragePath, engineCachesPath);
                sInitialized = true;
            } catch (Exception var6) {
                Log.e("FlutterMain", "Flutter initialization failed.", var6);
                throw new RuntimeException(var6);
            }
        }
    }
複製程式碼

該方法必須要在主執行緒中執行並且只執行一次。並且要等sResourceExtractor把資源copy到安裝包目錄下完成後才能往下繼續:

sResourceExtractor.waitForCompletion();

void waitForCompletion() {
        if (this.mExtractTask != null) {
            try {
                this.mExtractTask.get();
            } catch (ExecutionException | InterruptedException | CancellationException var2) {
                this.deleteFiles();
            }

        }
    }

private class ExtractTask extends AsyncTask<Void, Void, Void> {...}
複製程式碼

那麼拷貝的是哪些東西呢?看一個debug下的apk:

Flutter啟動流程簡析

其中vm開頭的是dartvm執行需要的,isolate就是我們用dart語言編寫的業務程式碼。

看下release包的apk,和debug有點不一樣,多出了幾個檔案。

Flutter啟動流程簡析

再回到之前的程式碼那裡,就是把assets目錄下的這些檔案拷貝到安裝包私有目錄下的flutter_assets.

程式碼裡面有很多的路徑名:

private static final String DEFAULT_KERNEL_BLOB = "kernel_blob.bin";
private static final String DEFAULT_FLUTTER_ASSETS_DIR = "flutter_assets";
private static String sAotSharedLibraryPath = "app.so";
private static String sAotVmSnapshotData = "vm_snapshot_data";
private static String sAotVmSnapshotInstr = "vm_snapshot_instr";
private static String sAotIsolateSnapshotData = "isolate_snapshot_data";
private static String sAotIsolateSnapshotInstr = "isolate_snapshot_instr";
private static String sFlx = "app.flx";
private static String sFlutterAssetsDir = "flutter_assets";
複製程式碼

接著會初始化一些目錄,包括appBundle路徑應用儲存目錄引擎快取目錄等。然後會呼叫JNI方法nativeInit在C++層初始化這些資訊,在FlutterMain中把這些路徑設定給setting,然後傳遞構造FlutterMain,再儲存到全域性變數g_flutter_main中。

// shell/platform/android/flutter_main.cc
static std::unique_ptr<FlutterMain> g_flutter_main;
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);
  };
	...
  // 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)));
}

複製程式碼

接著看上面第四部create FlutterNativeView.

3.FlutterNativeView

    public FlutterNativeView(Context context, boolean isBackgroundView) {
        this.mNextReplyId = 1;
        this.mPendingReplies = new HashMap();
        this.mContext = context;
        this.mPluginRegistry = new FlutterPluginRegistry(this, context);
        this.mFlutterJNI = new FlutterJNI();
        this.mFlutterJNI.setRenderSurface(new FlutterNativeView.RenderSurfaceImpl());
        this.mFlutterJNI.setPlatformMessageHandler(new FlutterNativeView.PlatformMessageHandlerImpl());
        this.mFlutterJNI.addEngineLifecycleListener(new FlutterNativeView.EngineLifecycleListenerImpl());
        this.attach(this, isBackgroundView);
        this.assertAttached();
        this.mMessageHandlers = new HashMap();
    }
複製程式碼

其中FlutterJNI是Java層和Flutter Engine通訊的橋樑,包括建立並啟動Flutter engine、當前FlutterView的Surface生命週期的通知、傳遞platform資料給dart層、回傳dart層呼叫platform層方法返回的結果資料等待。

然後會呼叫attach方法:

// FlutterNativeView.java
private void attach(FlutterNativeView view, boolean isBackgroundView) {
        this.mFlutterJNI.attachToNative(isBackgroundView);
}

// FlutterJNI.java
@UiThread
public void attachToNative(boolean isBackgroundView) {
     this.ensureNotAttachedToNative();
     this.nativePlatformViewId = this.nativeAttach(this, isBackgroundView);
}
複製程式碼

attachToNative方法中通過呼叫JNI方法nativeAttach將當前flutterJNI物件傳遞給c++層(後續一些dart層呼叫java層的方法就是通過該物件呼叫對應的方法實現的),得到c++層返回的nativePlatformViewId,這個值非常重要,是c++層AndroidShellHolder的物件指標值,後續會通過該值呼叫一系列c++層的方法執行操作,並將其儲存以供後續使用。

對應的C++方法如下, 通過之前初始化儲存在g_flutter_main物件中的settings值和傳入的java物件flutterJNI建立std::unique_ptr物件(該物件通過指標佔有並管理AndroidShellHolder物件),該物件有效的情況下會呼叫release方法返回其管理物件的指標並釋放物件的所有權,reinterpret_cast()方法將該AndroidShellHolder物件指標強制轉化為long型別的值並返回java層儲存。

// platform_view_android_jni.cc
// Called By Java

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;
  }
}
複製程式碼

接著看下很重要的一個類AndroiudShellHolder.

4.AndroiudShellHolder

程式碼比較長,先看下前半部分,傳入的引數is_background_view為false,會首先通過ThreadHost初始化三個執行緒ui_thread,gpu_thread, io_thread,而當前執行緒就是platform_thread.

  • platform_thread負責和Engine層的通訊
  • io_thread負責IO操作
  • gpu_thread執行GPU指令
  • ui_thread執行Dartisolate程式碼
// android_shell_holder.cc

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

  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};
  }
        
  ...
}
複製程式碼

四個執行緒會持有MessageLoop,通過他可以往執行緒新增工作任務, 具體可以參考另外一篇Flutter和原生之間的平臺通道實踐與原理的執行緒部分。接著會構造Shell

// android_shell_holder.cc

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

// shell.cc

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) {
  PerformInitializationTasks(settings);

  TRACE_EVENT0("flutter", "Shell::Create");

  auto vm = blink::DartVMRef::Create(settings);
  FML_CHECK(vm) << "Must be able to initialize the VM.";

  auto vm_data = vm->GetVMData();

  return Shell::Create(std::move(task_runners),             //
                       std::move(settings),                 //
                       vm_data->GetIsolateSnapshot(),       // isolate snapshot
                       blink::DartSnapshot::Empty(),        // shared snapshot
                       std::move(on_create_platform_view),  //
                       std::move(on_create_rasterizer),     //
                       std::move(vm)                        //
  );
}
複製程式碼

Shell Create中會根據傳入的settings引數通過blink::DartVMRef::Create構造Dart VM, 跟進去看看Dart VM的建立過程, VM只會構造一次,

// dart_vm_lifecycle.cc
DartVMRef DartVMRef::Create(Settings settings,
                            fml::RefPtr<DartSnapshot> vm_snapshot,
                            fml::RefPtr<DartSnapshot> isolate_snapshot,
                            fml::RefPtr<DartSnapshot> shared_snapshot) {
  std::lock_guard<std::mutex> lifecycle_lock(gVMMutex);

  // If there is already a running VM in the process, grab 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::lock_guard<std::mutex> dependents_lock(gVMDependentsMutex);

  gVMData.reset();
  gVMServiceProtocol.reset();
  gVMIsolateNameServer.reset();
  gVM.reset();

  // 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>();
  auto vm = DartVM::Create(std::move(settings),          //
                           std::move(vm_snapshot),       //
                           std::move(isolate_snapshot),  //
                           std::move(shared_snapshot),   //
                           isolate_name_server           //
  );

  if (!vm) {
    FML_LOG(ERROR) << "Could not create Dart VM instance.";
    return {nullptr};
  }

  gVMData = vm->GetVMData();
  gVMServiceProtocol = vm->GetServiceProtocol();
  gVMIsolateNameServer = isolate_name_server;
  gVM = vm;

  if (settings.leak_vm) {
    gVMLeak = vm;
  }

  return DartVMRef{std::move(vm)};
}
複製程式碼

然後通過DartVM::Create執行具體的構造過程,在Create中會呼叫DartVM建構函式, 通過執行dart::bin::BootstrapDartIo()方法引導啟動dart:io時間處理程式:

//dart_vm.cc

DartVM::DartVM(std::shared_ptr<const DartVMData> vm_data,
               std::shared_ptr<IsolateNameServer> isolate_name_server)
    : settings_(vm_data->GetSettings()),
      vm_data_(vm_data),
      isolate_name_server_(std::move(isolate_name_server)),
      service_protocol_(std::make_shared<ServiceProtocol>()) {
  TRACE_EVENT0("flutter", "DartVMInitializer");

  gVMLaunchCount++;

  FML_DCHECK(vm_data_);
  FML_DCHECK(isolate_name_server_);
  FML_DCHECK(service_protocol_);

  FML_DLOG(INFO) << "Attempting Dart VM launch for mode: "
                 << (IsRunningPrecompiledCode() ? "AOT" : "Interpreter");

  {
    TRACE_EVENT0("flutter", "dart::bin::BootstrapDartIo");
    dart::bin::BootstrapDartIo();

    if (!settings_.temp_directory_path.empty()) {
      dart::bin::SetSystemTempDirectory(settings_.temp_directory_path.c_str());
    }
  }
...
    
   DartUI::InitForGlobal();
          
   {
    TRACE_EVENT0("flutter", "Dart_Initialize");
    Dart_InitializeParams params = {};
    params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION;
    params.vm_snapshot_data =
        vm_data_->GetVMSnapshot().GetData()->GetSnapshotPointer();
    params.vm_snapshot_instructions =
        vm_data_->GetVMSnapshot().GetInstructionsIfPresent();
    params.create = reinterpret_cast<decltype(params.create)>(
        DartIsolate::DartIsolateCreateCallback);
    params.shutdown = reinterpret_cast<decltype(params.shutdown)>(
        DartIsolate::DartIsolateShutdownCallback);
    params.cleanup = reinterpret_cast<decltype(params.cleanup)>(
        DartIsolate::DartIsolateCleanupCallback);
    params.thread_exit = ThreadExitCallback;
    params.get_service_assets = GetVMServiceAssetsArchiveCallback;
    params.entropy_source = DartIO::EntropySource;
    char* init_error = Dart_Initialize(&params);
    ...
    }
   
}
複製程式碼

DartUI::InitForGlobal會註冊dart的各種本地方法,主要用於dart呼叫c++層方法,有點類似於java中的jni註冊:

// dart_ui.cc

void DartUI::InitForGlobal() {
  if (!g_natives) {
    g_natives = new tonic::DartLibraryNatives();
    Canvas::RegisterNatives(g_natives);
    CanvasGradient::RegisterNatives(g_natives);
    CanvasImage::RegisterNatives(g_natives);
    CanvasPath::RegisterNatives(g_natives);
    CanvasPathMeasure::RegisterNatives(g_natives);
    Codec::RegisterNatives(g_natives);
    DartRuntimeHooks::RegisterNatives(g_natives);
    EngineLayer::RegisterNatives(g_natives);
    FontCollection::RegisterNatives(g_natives);
    FrameInfo::RegisterNatives(g_natives);
    ImageFilter::RegisterNatives(g_natives);
    ImageShader::RegisterNatives(g_natives);
    IsolateNameServerNatives::RegisterNatives(g_natives);
    Paragraph::RegisterNatives(g_natives);
    ParagraphBuilder::RegisterNatives(g_natives);
    Picture::RegisterNatives(g_natives);
    PictureRecorder::RegisterNatives(g_natives);
    Scene::RegisterNatives(g_natives);
    SceneBuilder::RegisterNatives(g_natives);
    SceneHost::RegisterNatives(g_natives);
    SemanticsUpdate::RegisterNatives(g_natives);
    SemanticsUpdateBuilder::RegisterNatives(g_natives);
    Versions::RegisterNatives(g_natives);
    Vertices::RegisterNatives(g_natives);
    Window::RegisterNatives(g_natives);

    // Secondary isolates do not provide UI-related APIs.
    g_natives_secondary = new tonic::DartLibraryNatives();
    DartRuntimeHooks::RegisterNatives(g_natives_secondary);
    IsolateNameServerNatives::RegisterNatives(g_natives_secondary);
  }
}

// window.cc
void Window::RegisterNatives(tonic::DartLibraryNatives* natives) {
  natives->Register({
      {"Window_defaultRouteName", DefaultRouteName, 1, true},
      {"Window_scheduleFrame", ScheduleFrame, 1, true},
      {"Window_sendPlatformMessage", _SendPlatformMessage, 4, true},
      {"Window_respondToPlatformMessage", _RespondToPlatformMessage, 3, true},
      {"Window_render", Render, 2, true},
      {"Window_updateSemantics", UpdateSemantics, 2, true},
      {"Window_setIsolateDebugName", SetIsolateDebugName, 2, true},
      {"Window_reportUnhandledException", ReportUnhandledException, 2, true},
  });
}
複製程式碼

然後再DartVM中通過Dart_Initialize初始化Dart執行時環境,後面就不往下跟了,返回到shell.cc中,構造玩vm後會賦值給Shell, 再通過CreateShellOnPlatformThread構造Shell,該方法會在PlatformThread執行緒中執行。

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

  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),          //
                         settings,                                        //
                         isolate_snapshot = std::move(isolate_snapshot),  //
                         shared_snapshot = std::move(shared_snapshot),    //
                         on_create_platform_view,                         //
                         on_create_rasterizer                             //
  ]() mutable {
        shell = CreateShellOnPlatformThread(std::move(vm),
                                            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;
}
複製程式碼

接下來到CreateShellOnPlatformThread看看,程式碼比較多分成幾個部分來看, 首先呼叫new Shell構造,然後呼叫on_create_platform_view,這個方法在android_shell_holder.cc中通過Shell::Create傳遞過來的

// shell.cc
std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
    blink::DartVMRef vm,
    blink::TaskRunners task_runners,
    blink::Settings settings,
    fml::RefPtr<const blink::DartSnapshot> isolate_snapshot,
    fml::RefPtr<const blink::DartSnapshot> shared_snapshot,
    Shell::CreateCallback<PlatformView> on_create_platform_view,
    Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
  if (!task_runners.IsValid()) {
    FML_LOG(ERROR) << "Task runners to run the shell were invalid.";
    return nullptr;
  }

  auto shell =
      std::unique_ptr<Shell>(new Shell(std::move(vm), 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;
  }
  ...
}
複製程式碼

看下on_create_platform_view,在這裡會構造PlatformViewAndroid並且交給platform_view管理

// android_shell_holder.cc
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.cc中接著往下看,接著會在IO Thread中構造IOManager物件並且交給io_manager管理:

  // 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   //
  ]() {
        TRACE_EVENT0("flutter", "ShellSetupIOSubsystem");
        io_manager = std::make_unique<IOManager>(
            platform_view->CreateResourceContext(), io_task_runner);
        io_latch.Signal();
      });
  io_latch.Wait();
複製程式碼

接著會在GPU Thread中構造Rasterizer物件並且交給rasterizer管理,on_create_rasterizer也是在android_shell_holder.cc中通過Shell::Create傳遞過來的

  // 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     //
  ]() {
        TRACE_EVENT0("flutter", "ShellSetupGPUSubsystem");
        if (auto new_rasterizer = on_create_rasterizer(*shell)) {
          rasterizer = std::move(new_rasterizer);
          snapshot_delegate = rasterizer->GetSnapshotDelegate();
        }
        gpu_latch.Signal();
      });

  gpu_latch.Wait();
複製程式碼

接著在UIThread中建立Engine,並且交給engine管理:

  // 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 {
        TRACE_EVENT0("flutter", "ShellSetupUISubsystem");
        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();
複製程式碼

最後通過shell->Setup方法將platform_view engine rasterizer io_manager四個物件交給 Shell物件管理:

  // 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;
複製程式碼

再回到前面的android_shell_holder.cc中,通過Shell::Create()建立完成後的shell物件返回給AndroidShellHolder物件持有。到這裡整體思路就清晰了,Embedder層通過Shell物件與Engine層建立了連線,後續的一切操作通過Shell物件進行。而Shell物件又通過AndroidShellHolder物件持有,AndroidShellHolder物件指標值又返回給了java層,然後java層在呼叫JNI方法的時候將這個指標值傳遞過去便能拿到Embedder層的AndroidShellHolder物件,進而通過Shell物件向engine層傳送一系列操作指令。

5.RunBundle

經過上面的流程,已經為dart層程式碼執行建立好了執行時環境,接下來就是載入dart層相關的程式碼了。

再回到java層的FlutterActivityDelegate中的onCreate程式碼:

//FlutterActivityDelegate.java/onCreate
if (!this.loadIntent(this.activity.getIntent())) {
            String appBundlePath = FlutterMain.findAppBundlePath(this.activity.getApplicationContext());
            if (appBundlePath != null) {
                this.runBundle(appBundlePath);
            }

        }

//FlutterActivityDelegate.java/runBundle
    private void runBundle(String appBundlePath) {
        if (!this.flutterView.getFlutterNativeView().isApplicationRunning()) {
            FlutterRunArguments args = new FlutterRunArguments();
            ArrayList<String> bundlePaths = new ArrayList();
            ResourceUpdater resourceUpdater = FlutterMain.getResourceUpdater();
            if (resourceUpdater != null) {
                File patchFile = resourceUpdater.getInstalledPatch();
                JSONObject manifest = resourceUpdater.readManifest(patchFile);
                if (resourceUpdater.validateManifest(manifest)) {
                    bundlePaths.add(patchFile.getPath());
                }
            }

            bundlePaths.add(appBundlePath);
            args.bundlePaths = (String[])bundlePaths.toArray(new String[0]);
            args.entrypoint = "main";
            this.flutterView.runFromBundle(args);
        }

    }
複製程式碼

呼叫自己的runBundle函式,在if語句裡面可以看到資源提取的程式碼,這裡是Flutter預埋的動態更新程式碼,目前應該還沒起作用,然後會呼叫FlutterView runFromBundle

// FlutterView.java
public void runFromBundle(FlutterRunArguments args) {
        this.assertAttached();
        this.preRun();
        this.mNativeView.runFromBundle(args);
        this.postRun();
}
複製程式碼

java層最終會調到FlutterJNI中,其中nativePlatformViewId就是AndroidShellHolderjava層的指標值,此時的prioritizedBundlePaths陣列中只有一個值類似/data/data/包名/flutter/flutter_assets/的路徑值,entrypointFunctionNamemainpathToEntrypointFunctionnull

// FlutterJNI.java
  @UiThread
  public void runBundleAndSnapshotFromLibrary(
      @NonNull String[] prioritizedBundlePaths,
      @Nullable String entrypointFunctionName,
      @Nullable String pathToEntrypointFunction,
      @NonNull AssetManager assetManager
  ) {
    ensureAttachedToNative();
    nativeRunBundleAndSnapshotFromLibrary(
        nativePlatformViewId,
        prioritizedBundlePaths,
        entrypointFunctionName,
        pathToEntrypointFunction,
        assetManager
    );
  }

  private native void nativeRunBundleAndSnapshotFromLibrary(
      long nativePlatformViewId,
      @NonNull String[] prioritizedBundlePaths,
      @Nullable String entrypointFunctionName,
      @Nullable String pathToEntrypointFunction,
      @NonNull AssetManager manager
  );
複製程式碼

後面就到了JNI層了,在PlatformViewAndrod中:

// platform_view_android_jni.cc
{
          .name = "nativeRunBundleAndSnapshotFromLibrary",
          .signature = "(J[Ljava/lang/String;Ljava/lang/String;"
                       "Ljava/lang/String;Landroid/content/res/AssetManager;)V",
          .fnPtr =
              reinterpret_cast<void*>(&shell::RunBundleAndSnapshotFromLibrary),
},

// RunBundleAndSnapshotFromLibrary
static void RunBundleAndSnapshotFromLibrary(JNIEnv* env,
                                            jobject jcaller,
                                            jlong shell_holder,
                                            jobjectArray jbundlepaths,
                                            jstring jEntrypoint,
                                            jstring jLibraryUrl,
                                            jobject jAssetManager) {
  auto asset_manager = std::make_shared<blink::AssetManager>();
  for (const auto& bundlepath :
       fml::jni::StringArrayToVector(env, jbundlepaths)) {
    if (bundlepath.empty()) {
      continue;
    }

    // If we got a bundle path, attempt to use that as a directory asset
    // bundle or a zip asset bundle.
    const auto file_ext_index = bundlepath.rfind(".");
    if (bundlepath.substr(file_ext_index) == ".zip") {
      asset_manager->PushBack(std::make_unique<blink::ZipAssetStore>(
          bundlepath, "assets/flutter_assets"));

    } else {
      asset_manager->PushBack(
          std::make_unique<blink::DirectoryAssetBundle>(fml::OpenDirectory(
              bundlepath.c_str(), false, fml::FilePermission::kRead)));

      // Use the last path component of the bundle path to determine the
      // directory in the APK assets.
      const auto last_slash_index = bundlepath.rfind("/", bundlepath.size());
      if (last_slash_index != std::string::npos) {
        auto apk_asset_dir = bundlepath.substr(
            last_slash_index + 1, bundlepath.size() - last_slash_index);

        asset_manager->PushBack(std::make_unique<blink::APKAssetProvider>(
            env,                       // jni environment
            jAssetManager,             // asset manager
            std::move(apk_asset_dir))  // apk asset dir
        );
      }
    }
  }
複製程式碼

上面邏輯首先通過bundlePath建立DirectoryAssetBundle物件交給asset_manager物件管理,然後欻功能鍵執行配置物件config,通過ANDROID_SHELL_HOLDER->Launch(std::move(config));根據執行配置資訊啟動,ANDROID_SHELL_HOLDER是一個巨集,通過將java層持有的AndroidShellHolder指標值強轉為AndroidShellHolder物件指標,這樣就可以呼叫它的方法了。

// platform_view_android_jni.cc
#define ANDROID_SHELL_HOLDER \
  (reinterpret_cast<shell::AndroidShellHolder*>(shell_holder))
複製程式碼

再看到AndroidShellHolder中的方法Launch,就是到shell中取出engine,然後在UIThread中執行engine->Run:

void AndroidShellHolder::Launch(RunConfiguration config) {
  if (!IsValid()) {
    return;
  }

  shell_->GetTaskRunners().GetUITaskRunner()->PostTask(
      fml::MakeCopyable([engine = shell_->GetEngine(),  //
                         config = std::move(config)     //
  ]() mutable {
        FML_LOG(INFO) << "Attempting to launch engine configuration...";
        if (!engine || engine->Run(std::move(config)) ==
                           shell::Engine::RunStatus::Failure) {
          FML_LOG(ERROR) << "Could not launch engine in configuration.";
        } else {
          FML_LOG(INFO) << "Isolate for engine configuration successfully "
                           "started and run.";
        }
      }));
}
複製程式碼

再看下engine->Run:

// engine.cc
Engine::RunStatus Engine::Run(RunConfiguration configuration) {
  if (!configuration.IsValid()) {
    FML_LOG(ERROR) << "Engine run configuration was invalid.";
    return RunStatus::Failure;
  }

  auto isolate_launch_status =
      PrepareAndLaunchIsolate(std::move(configuration));
 ...

  return isolate_running ? Engine::RunStatus::Success
                         : Engine::RunStatus::Failure;
}

shell::Engine::RunStatus Engine::PrepareAndLaunchIsolate(
    RunConfiguration configuration) {
  ...

  if (configuration.GetEntrypointLibrary().empty()) {
    if (!isolate->Run(configuration.GetEntrypoint())) {
      FML_LOG(ERROR) << "Could not run the isolate.";
      return RunStatus::Failure;
    }
  } else {
    if (!isolate->RunFromLibrary(configuration.GetEntrypointLibrary(),
                                 configuration.GetEntrypoint())) {
      FML_LOG(ERROR) << "Could not run the isolate.";
      return RunStatus::Failure;
    }
  }

  return RunStatus::Success;
}
複製程式碼

最終調到DartIsolateRun方法, 通過DartInvokeField執行到Dart層的main()方法入口,這樣整個Dart程式碼就跑起來了,Flutter介面也就顯示到FlutterView中。

// dart_isolate.cc
FML_WARN_UNUSED_RESULT
bool DartIsolate::Run(const std::string& entrypoint_name, 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()));

  if (!InvokeMainEntrypoint(user_entrypoint_function)) {
    return false;
  }

  phase_ = Phase::Running;
  FML_DLOG(INFO) << "New isolate is in the running state.";

  if (on_run) {
    on_run();
  }
  return true;
}

FML_WARN_UNUSED_RESULT
static bool InvokeMainEntrypoint(Dart_Handle user_entrypoint_function) {
  if (tonic::LogIfError(user_entrypoint_function)) {
    FML_LOG(ERROR) << "Could not resolve main entrypoint function.";
    return false;
  }

  Dart_Handle start_main_isolate_function =
      tonic::DartInvokeField(Dart_LookupLibrary(tonic::ToDart("dart:isolate")),
                             "_getStartMainIsolateFunction", {});

  if (tonic::LogIfError(start_main_isolate_function)) {
    FML_LOG(ERROR) << "Could not resolve main entrypoint trampoline.";
    return false;
  }

  if (tonic::LogIfError(tonic::DartInvokeField(
          Dart_LookupLibrary(tonic::ToDart("dart:ui")), "_runMainZoned",
          {start_main_isolate_function, user_entrypoint_function}))) {
    FML_LOG(ERROR) << "Could not invoke the main entrypoint.";
    return false;
  }

  return true;
}
複製程式碼

6.總結

整個程式碼比較長,簡單總結就是在Android平臺上Flutter是顯示到FlutterView上的,FlutterView會通過FlutterNativeView呼叫到FlutterJNI,在FlutterJNI會持有一個很重要的物件AndroidShellHolder,而 AndroidShellHolder會持有shell物件, Embedder層通過Shell物件與Engine層建立了連線,後續的一切操作通過Shell物件進行。AndroidShellHolder物件指標值又返回給了java層,然後FlutterJNI在呼叫JNI方法的時候將這個指標值傳遞過去便能拿到Embedder層的AndroidShellHolder物件,進而通過Shell物件向engine層傳送一系列操作指令。Engine物件會呼叫dart層程式碼執行。

參考連結:

相關文章