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模塊就啓動成功。java

1.Android平臺代碼分析

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

首先看到FlutterApplication中的onCreatec++

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

接着到FlutterMain中:shell

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到私有目錄下,看一個手機上私有目錄下的截圖數組

最後調用JNI方法nativeRecordStartTimestamp記錄到C++層。緩存

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

// 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.根據系統版本設置狀態欄樣式ide

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:

其中vm開頭的是dartvm執行須要的,isolate就是咱們用dart語言編寫的業務代碼。

看下release包的apk,和debug有點不同,多出了幾個文件。

再回到以前的代碼那裏,就是把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層代碼執行。

參考連接:

相關文章
相關標籤/搜索