flutter啟動過程分析

微信公眾號:Android部落格,文末有二維碼

個人網(wǎng)站:chengang.plus

啟動過程分析

原圖地址是:https://ftp.bmp.ovh/imgs/2020/04/f92a2d6c47bcf3f6.jpg

https://ftp.bmp.ovh/imgs/2020/04/f92a2d6c47bcf3f6.jpg

1、 初始化

一般的,都有一個入口Activity俘枫,這個Activity繼承自FlutterActivity赫蛇。

從入口Activity的oncreate方法開始分析,首先調(diào)用FlutterMain.startInitialization(this)矿卑,如果我們自定義了Application(FlutterApplication),可以在Application的onCreate方法中調(diào)用悄但。

startInitialization最終會調(diào)用到FlutterLoader的startInitialization方法棠隐,在這個方法中主要干了以下幾件事:

  • 初始化系統(tǒng)配置
  • 在debug或JIT模式下復(fù)制assert文件夾下的文件到data目錄下。從apk包的assets目錄下檐嚣,將vm_snapshot_data,isolate_snapshot_data,kernel_blob.bin文件復(fù)制到/data/data/package name/app_flutter/flutter_assets/目錄下助泽。
  • 加載libflutter.so庫
  • 計算初始化時間,并傳遞到native層

初始化操作為之后運行準(zhǔn)備了flutter環(huán)境嚎京,也準(zhǔn)備好了運行所需要的資源

2嗡贺、創(chuàng)建FlutterView

創(chuàng)建過程中比較重要的幾行代碼如下:

io\flutter\view\FlutterView.java

public FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) {
    mNativeView = new FlutterNativeView(activity.getApplicationContext());
    mNativeView.attachViewAndActivity(this, activity);
    mSurfaceCallback = new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                mNativeView.getFlutterJNI().onSurfaceCreated(holder.getSurface());
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                mNativeView.getFlutterJNI().onSurfaceChanged(width, height);
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                mNativeView.getFlutterJNI().onSurfaceDestroyed();
            }
        };
}

其中涉及FlutterActivityFlutterView鞍帝,FlutterNativeView诫睬,FlutterActivityDelegateFlutterJNI這幾個主要的類膜眠。

  • FlutterActivity主要處理各個生命周期以及各種系統(tǒng)回調(diào)。
  • FlutterView其實是一個SurfaceView溜嗜,在SurfaceHolder.Callback中處理View的各個狀態(tài)宵膨,這關(guān)系到整個界面的展現(xiàn)。
  • FlutterNativeView其實不是個View炸宵,只是一個中間人辟躏。因為他持有FlutterJNI和DartExecutor對象,將View的狀態(tài)和消息傳遞到native層
  • FlutterActivityDelegate土全,代理捎琐。創(chuàng)建了FlutterView和FlutterNativeView,然后將Activity的生命周期和各種回調(diào)給到FlutterView處理
  • FlutterJNI裹匙,被FlutterView調(diào)用瑞凑,然后調(diào)用native代碼,并接收native的回調(diào)

2.1 創(chuàng)建FlutterNativeView

主要的幾行代碼如下:

io\flutter\view\FlutterNativeView.java

public FlutterNativeView(@NonNull Context context, boolean isBackgroundView) {
    mContext = context;
    mPluginRegistry = new FlutterPluginRegistry(this, context);
    mFlutterJNI = new FlutterJNI();
    mFlutterJNI.addIsDisplayingFlutterUiListener(flutterUiDisplayListener);
    this.dartExecutor = new DartExecutor(mFlutterJNI, context.getAssets());
    mFlutterJNI.addEngineLifecycleListener(new EngineLifecycleListenerImpl());
    attach(this, isBackgroundView);
}

2.1.1 先持有FlutterJNI對象概页,后續(xù)用于與native交互

2.1.2 attach

最終調(diào)用到了FlutterJNI的attachToNative方法籽御,并調(diào)用native的nativeAttach方法《璩祝看看這個nativeAttach方法注冊的地方:

shell\platform\android\platform_view_android_jni.cc

{
  .name = "nativeAttach",
  .signature = "(Lio/flutter/embedding/engine/FlutterJNI;Z)J",
  .fnPtr = reinterpret_cast<void*>(&AttachJNI),
}

被注冊到了AttachJNI方法技掏,看看這個方法:

shell\platform\android\platform_view_android_jni.cc

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

這里初始化構(gòu)造函數(shù)AndroidShellHolder

2.1.3 AndroidShellHolder

初始化過程中比較重要的代碼如下:

shell\platform\android\android_shell_holder.cc

AndroidShellHolder::AndroidShellHolder(){
    thread_host_ = {thread_label, ThreadHost::Type::UI | ThreadHost::Type::GPU | ThreadHost::Type::IO};
    Shell::CreateCallback<PlatformView> on_create_platform_view = 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
    ); 
    Shell::CreateCallback<Rasterizer> on_create_rasterizer = [](Shell& shell) {
        return std::make_unique<Rasterizer>(shell, shell.GetTaskRunners());
    };
    fml::RefPtr<fml::TaskRunner> platform_runner = fml::MessageLoop::GetCurrent().GetTaskRunner();
    fml::RefPtr<fml::TaskRunner> gpu_runner = thread_host_.gpu_thread->GetTaskRunner();
    fml::RefPtr<fml::TaskRunner> ui_runner = thread_host_.ui_thread->GetTaskRunner();
    fml::RefPtr<fml::TaskRunner> io_runner = thread_host_.io_thread->GetTaskRunner();
    
    flutter::TaskRunners task_runners(thread_label,     // label
                                    platform_runner,  // platform
                                    gpu_runner,       // raster
                                    ui_runner,        // ui
                                    io_runner         // io
    );
    shell_ = Shell::Create(task_runners,        // task runners
                    GetDefaultWindowData(),   // window data
                    settings_,                // settings
                    on_create_platform_view,  // platform view create callback
                    on_create_rasterizer      // rasterizer create callback
    );
    task_runners.GetGPUTaskRunner()->PostTask([]() {});
    task_runners.GetUITaskRunner()->PostTask([]() {)};
}

這個類比較重要项鬼,可以分幾個部分解析:

  • 1哑梳、thread_host_是一個ThreadHost結(jié)構(gòu)體的對象,是platform_thread绘盟,ui_thread鸠真,gpu_thread悯仙,io_thread這個四個線程的集合。

進(jìn)一步查看可以發(fā)現(xiàn)Thread類持有一個TaskRunner對象弧哎。

  • 2雁比、PlatformViewAndroid,第二步調(diào)用初始化構(gòu)造函數(shù)撤嫩,創(chuàng)建一個on_create_platform_view 對象偎捎,這個類繼承自PlatformView,做平臺View的初始化工作
  • 3序攘、四個TaskRunner,看看他的初始化:

Thread初始化

shell\platform\fuchsia\flutter\thread.cc

Thread::Thread(const std::string& name) : joined_(false) {
    fml::RefPtr<fml::TaskRunner> runner;
    thread_ = std::make_unique<std::thread>([&latch, &runner, name]() -> void {
        SetCurrentThreadName(name);
        fml::MessageLoop::EnsureInitializedForCurrentThread();
        auto& loop = MessageLoop::GetCurrent();
        runner = loop.GetTaskRunner();
        latch.Signal();
        loop.Run();
    });
}

在EnsureInitializedForCurrentThread方法中會初始化MessageLoop構(gòu)造函數(shù)茴她,然后獲取一個loop對象,從這個loop對象里獲取TaskRunner程奠。

MessageLoop構(gòu)造函數(shù)

如下:

fml\message_loop.cc

MessageLoop::MessageLoop()
    : loop_(MessageLoopImpl::Create()),
      task_runner_(fml::MakeRefCounted<fml::TaskRunner>(loop_)) {
}

可見此時初始化了一個MessageLoopImpl構(gòu)造函數(shù)丈牢。

MessageLoopImpl構(gòu)造函數(shù)

fml\message_loop_impl.cc

fml::RefPtr<MessageLoopImpl> MessageLoopImpl::Create() {
#if OS_MACOSX
  return fml::MakeRefCounted<MessageLoopDarwin>();
#elif OS_ANDROID
  return fml::MakeRefCounted<MessageLoopAndroid>();
#elif OS_FUCHSIA
  return fml::MakeRefCounted<MessageLoopFuchsia>();
#elif OS_LINUX
  return fml::MakeRefCounted<MessageLoopLinux>();
#elif OS_WIN
  return fml::MakeRefCounted<MessageLoopWin>();
#else
  return nullptr;
#endif
}

以MessageLoopAndroid為例,MessageLoopAndroid的父類是MessageLoopImpl瞄沙。

MessageLoopImpl構(gòu)造函數(shù)

如下

fml\message_loop_impl.cc

MessageLoopImpl::MessageLoopImpl()
    : task_queue_(MessageLoopTaskQueues::GetInstance()),
      queue_id_(task_queue_->CreateTaskQueue()),
      terminated_(false) {
  task_queue_->SetWakeable(queue_id_, this);
}

這里可以看到MessageLoopImpl創(chuàng)建了消息隊列己沛。

fml\platform\android\message_loop_android.cc

MessageLoopAndroid::MessageLoopAndroid(){
    int add_result = ::ALooper_addFd(looper_.get(),          // looper
                               timer_fd_.get(),        // fd
                               ALOOPER_POLL_CALLBACK,  // ident
                               kWakeEvents,            // events
                               read_event_fd,          // callback
                               this                    // baton
  );
}

初始化完成之后,有一個loop.run方法,實際上調(diào)用的是對應(yīng)平臺的Run方法:

fml\platform\android\message_loop_android.cc

void MessageLoopAndroid::Run() {
  running_ = true;
  while (running_) {
    int result = ::ALooper_pollOnce(-1,  //infinite timeout
        nullptr,  // out fd,
        nullptr,  // out events,
        nullptr   // out data
    );
  }
}

這里運用了linux的poll機制距境。

可以看到這里循環(huán)等待消息處理申尼。

接下來看看runner = loop.GetTaskRunner()方法,要探究一下這個TaskRunner是怎么初始化的垫桂。

再回到MessageLoop構(gòu)造函數(shù)师幕,還是之前貼的代碼,可以看到有一行代碼诬滩,構(gòu)造函數(shù)的初始化成員變量霹粥,如下:

fml\message_loop.cc

task_runner_(fml::MakeRefCounted<fml::TaskRunner>(loop_))

這個loop_實際是MessageLoopImpl類型,而GetTaskRunner()方法定義在MessageLoop類中疼鸟,返回的就是task_runner_后控。

可見TaskRunner無非就是持有一個loop對象,并將task提交給MessageLoopImpl執(zhí)行空镜。而從消息隊列中取對象執(zhí)行的時候是在每一個對應(yīng)的線程中忆蚀。

2.1.4 Shell::Create

這個方法也很重要,因為在這里我們可以看到他初始化了Engine姑裂。

直接看比較重要的兩個初始化構(gòu)造函數(shù):

第一個:

std::unique_ptr<Shell> Shell::Create(){
    auto vm = DartVMRef::Create(settings);
    auto vm_data = vm->GetVMData();
}

在這里啟動Dart虛擬機:

DartVMRef DartVMRef::Create(Settings settings,
        fml::RefPtr<DartSnapshot> vm_snapshot,
        fml::RefPtr<DartSnapshot> isolate_snapshot) {
    if (auto vm = gVM.lock()) {
        return DartVMRef{std::move(vm)};
    }
    auto vm = DartVM::Create(std::move(settings),  //
        std::move(vm_snapshot),       //
        std::move(isolate_snapshot),  //
        isolate_name_server           //
    );
    return DartVMRef{std::move(vm)};
}

如果已經(jīng)存在一個vm的對象就直接返回馋袜,否則創(chuàng)建一個:

std::shared_ptr<DartVM> DartVM::Create(){
    auto vm_data = DartVMData::Create(settings, //
        std::move(vm_snapshot),      //
        std::move(isolate_snapshot)  //
  );
    return std::shared_ptr<DartVM>(
        new DartVM(std::move(vm_data), std::move(isolate_name_server)));
}

先創(chuàng)建DartVMData類型對象,看看是怎么創(chuàng)建的:

std::shared_ptr<const DartVMData> DartVMData::Create(
    Settings settings,
    fml::RefPtr<DartSnapshot> vm_snapshot,
    fml::RefPtr<DartSnapshot> isolate_snapshot) {
    if (!vm_snapshot || !vm_snapshot->IsValid()) {
        vm_snapshot = DartSnapshot::VMSnapshotFromSettings(settings);
    }
    if (!isolate_snapshot || !isolate_snapshot->IsValid()) {
        isolate_snapshot = DartSnapshot::IsolateSnapshotFromSettings(settings);
    }
    return std::shared_ptr<const DartVMData>(new DartVMData(
        std::move(settings),         //
        std::move(vm_snapshot),      //
        std::move(isolate_snapshot)  //
    ));
}

這里的代碼比較核心舶斧,因為我們在應(yīng)用層寫的dart代碼能夠運行起來欣鳖,主要依靠這兩個對象。一個是跟VM有關(guān)的叫core snapshot茴厉,一個是與isolate有關(guān)的泽台,叫isolate snapshot什荣。
初始化DartVMData工作完成之后,返回他的對象給DartVM怀酷。

自此稻爬,DartVM對象算是建立起來了,并啟動了VM虛擬機蜕依。

第二個:

std::unique_ptr<Shell> Shell::Create(){
    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),          //
        window_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),      //
            window_data,                  //
            settings,                     //
            std::move(isolate_snapshot),  //
            on_create_platform_view,      //
            on_create_rasterizer          //
        );
        latch.Signal();
      }));
  latch.Wait();
  return shell;
}

AutoResetWaitableEvent其實是一個線程安全的消息同步處理類桅锄。當(dāng)調(diào)用Signal方法時表示解除阻塞,返回數(shù)據(jù)样眠;當(dāng)調(diào)用Wait方法的時候表示阻塞當(dāng)前消息友瘤,等待返回。

這里主要看看CreateShellOnPlatformThread方法:

std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(){
    auto shell = std::unique_ptr<Shell>(new Shell(std::move(vm), task_runners, settings));
    auto engine_future = engine_promise.get_future();
    fml::TaskRunner::RunNowOrPostTask(
        shell->GetTaskRunners().GetUITaskRunner(),
        fml::MakeCopyable([&engine_promise, //
        shell = shell.get(),                //
        &dispatcher_maker,                  //
        &window_data,                       //
        isolate_snapshot = std::move(isolate_snapshot),  //
        vsync_waiter = std::move(vsync_waiter),          //
        &weak_io_manager_future,                         //
        &snapshot_delegate_future,                       //
        &unref_queue_future                              //
  ]() mutable {
        engine_promise.set_value(std::make_unique<Engine>(
            *shell,                         //
            dispatcher_maker,               //
            *shell->GetDartVM(),            //
            std::move(isolate_snapshot),    //
            task_runners,                   //
            window_data,                    //
            shell->GetSettings(),           //
            std::move(animator),            //
            weak_io_manager_future.get(),   //
            unref_queue_future.get(),       //
            snapshot_delegate_future.get()  //
            ));
      }));
      return shell;
}

到這里可以看到開始對Engine初始化了檐束”柩恚看看Engine類的代碼注釋:

Engine是Shell的一個組件,并通過UI TaskRunner創(chuàng)建被丧。他負(fù)責(zé)管理根isolate的需求任務(wù)以及這些isolate的運行時盟戏。Engine只能在UI TaskRunner里面被創(chuàng)建,調(diào)用甥桂,回收柿究。

flutter應(yīng)用的根isolate獲取窗口的綁定對象,通過這些對象格嘁,根isolate可以調(diào)度幀笛求,提交視圖層級渲染廊移,請求圖片解壓縮糕簿,并將這些圖片提交給GPU等。非根isolate不具備以上的那些能力狡孔,而是活在VM虛擬機管理的線程池中懂诗。

Engine負(fù)責(zé)根isolate的整個生命周期,當(dāng)engine被回收的時候苗膝,他的所有者(Shell)假設(shè)根isolate已經(jīng)關(guān)閉了并且將適合的資源回收殃恒,然而一個Engine只能持有一個根isolate單實例,一旦有請求辱揭,engine可以將這個根isolate重啟离唐。這也是為什么冷啟動開發(fā)場景被支持的原因。

Engine被初始化創(chuàng)建的時候问窃,根isolate就被創(chuàng)建了亥鬓,但是并不直接運行起來,只有等到Engine::Run被調(diào)用的時候域庇,才會運行起來嵌戈。

看看Engine的初始化:

shell\common\engine.cc

Engine::Engine(Delegate& delegate,
               const PointerDataDispatcherMaker& dispatcher_maker,
               DartVM& vm,
               fml::RefPtr<const DartSnapshot> isolate_snapshot,
               TaskRunners task_runners,
               const WindowData window_data,
               Settings settings,
               std::unique_ptr<Animator> animator,
               fml::WeakPtr<IOManager> io_manager,
               fml::RefPtr<SkiaUnrefQueue> unref_queue,
               fml::WeakPtr<SnapshotDelegate> snapshot_delegate){
      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
      window_data,                           // window data
      settings_.isolate_create_callback,     // isolate create callback
      settings_.isolate_shutdown_callback,   // isolate shutdown callback
      settings_.persistent_isolate_data      // persistent isolate data
  );
}

這里RuntimeController被初始化覆积,看看他的構(gòu)造函數(shù):

runtime\runtime_controller.cc

RuntimeController::RuntimeController(){
auto strong_root_isolate = DartIsolate::CreateRootIsolate(
        vm_->GetVMData()->GetSettings(),  //
        isolate_snapshot_,                //
        task_runners_,                    //
        std::make_unique<Window>(this),   //
        snapshot_delegate_,               //
        io_manager_,                      //
        unref_queue_,                     //
        image_decoder_,                   //
        p_advisory_script_uri,            //
        p_advisory_script_entrypoint,     //
        nullptr,                          //
        isolate_create_callback_,         //
        isolate_shutdown_callback_        //
    ).lock();
}

創(chuàng)建引擎的同時創(chuàng)建根isolate谈秫。

runtime\dart_isolate.cc

std::weak_ptr<DartIsolate> DartIsolate::CreateRootIsolate(){
    auto isolate_group_data = std::make_unique<std::shared_ptr<DartIsolateGroupData>>(
        std::shared_ptr<DartIsolateGroupData>(new DartIsolateGroupData(
            settings,                     // settings
            std::move(isolate_snapshot),  // isolate snapshot
            advisory_script_uri,          // advisory URI
            advisory_script_entrypoint,   // advisory entrypoint
            nullptr,                      // child isolate preparer
            isolate_create_callback,      // isolate create callback
            isolate_shutdown_callback     // isolate shutdown callback
    )));

    auto isolate_data = std::make_unique<std::shared_ptr<DartIsolate>>(
        std::shared_ptr<DartIsolate>(new DartIsolate(
            settings,                      // settings
            task_runners,                  // task runners
            std::move(snapshot_delegate),  // snapshot delegate
            std::move(io_manager),         // IO manager
            std::move(unref_queue),        // Skia unref queue
            std::move(image_decoder),      // Image Decoder
            advisory_script_uri,           // advisory URI
            advisory_script_entrypoint,    // advisory entrypoint
            true                           // is_root_isolate
    )));
    DartErrorString error;
    Dart_Isolate vm_isolate = CreateDartIsolateGroup(
        std::move(isolate_group_data),
        std::move(isolate_data), 
        flags, 
        error.error());
    std::shared_ptr<DartIsolate>* root_isolate_data = static_cast<std::shared_ptr<DartIsolate>*>(Dart_IsolateData(vm_isolate));

    (*root_isolate_data)->SetWindow(std::move(window));

    return (*root_isolate_data)->GetWeakIsolatePtr();
}

這里先為DartIsolateGroup創(chuàng)建組數(shù)據(jù)查辩,然后為DartIsolateGroup創(chuàng)建子DartIsolate没咙。

到這里我們可以看到DartVM鹃觉,Engine于樟,Shell創(chuàng)建先后關(guān)系是:AndroidShellHolder -> Shell -> TaskRunner -> DartVm -> Engine -> RuntimeController -> DartIsolate衬以。

總結(jié)

追溯上述源碼總結(jié)AndroidShellHolder的構(gòu)造函數(shù)便贵,可以發(fā)現(xiàn)最主要的是創(chuàng)建了DartVM嘲碧,Engine偿短,DartIsolate欣孤,Shell四個對象,啟動DartVM虛擬機昔逗,為上層應(yīng)用程序被Launch做準(zhǔn)備降传。

2.2 處理SurfaceHolder.Callback回調(diào)

先看onSurfaceCreated回調(diào),這個函數(shù)最終會調(diào)用到FlutterJNI的nativeSurfaceCreated方法,它被注冊到了shell\platform\android\platform_view_android_jni.cc文件中的SurfaceCreated的方法:

static void SurfaceCreated(JNIEnv* env,
                           jobject jcaller,
                           jlong shell_holder,
                           jobject jsurface) {
    auto window = fml::MakeRefCounted<AndroidNativeWindow>(ANativeWindow_fromSurface(env, jsurface));
    ANDROID_SHELL_HOLDER->GetPlatformView()->NotifyCreated(std::move(window));
}

這里的ANDROID_SHELL_HOLDER就是2.1.3中初始化的AndroidShellHolder對象勾怒,而GetPlatformView()方法獲取的是PlatformViewAndroid類型的對象.

2.2.1 PlatformViewAndroid

看看PlatformViewAndroid的NotifyCreated方法:

void PlatformViewAndroid::NotifyCreated(
    fml::RefPtr<AndroidNativeWindow> native_window) {
  if (android_surface_) {
    InstallFirstFrameCallback();

    fml::AutoResetWaitableEvent latch;
    fml::TaskRunner::RunNowOrPostTask(
        task_runners_.GetGPUTaskRunner(),
        [&latch, surface = android_surface_.get(),
         native_window = std::move(native_window)]() {
          surface->SetNativeWindow(native_window);
          latch.Signal();
        });
    latch.Wait();
  }

  PlatformView::NotifyCreated();
}
  • InstallFirstFrameCallback

該方法啟動了platform TaskRunner婆排,同時通知java層,第一幀已經(jīng)渲染好了笔链。最終調(diào)用到了shell\platform\android\platform_view_android_jni.cc中的FlutterViewOnFirstFrame方法:

void FlutterViewOnFirstFrame(JNIEnv* env, jobject obj) {
  env->CallVoidMethod(obj, g_on_first_frame_method);
  FML_CHECK(CheckException(env));
}

g_on_first_frame_method對應(yīng)的其實是java層的onFirstFrame方法段只,其實是在FlutterJNI方法中:

g_on_first_frame_method = env->GetMethodID(g_flutter_jni_class->obj(), "onFirstFrame", "()V");

看看FlutterJNI中的這個方法:

void onFirstFrame() {
    for (FlutterUiDisplayListener listener : flutterUiDisplayListeners) {
      listener.onFlutterUiDisplayed();
    }
}

這個onFlutterUiDisplayed最終回調(diào)給了FlutterNativeView中的flutterUiDisplayListener對象,而他收到消息之后鉴扫,調(diào)用FlutterView的onFirstFrame方法赞枕,這個方法中主要做消息分發(fā),誰監(jiān)聽了FirstFrameListener坪创,就分發(fā)消息給誰炕婶。

其實還是FlutterView自己監(jiān)聽了,只不過是在FlutterActivityDelegate類中完成的莱预,這個實際到第一屏啟動頁的處理柠掂,后面再說。

接下來啟動了gpu TaskRunner依沮。

  • PlatformView::NotifyCreated()
    看看這個方法:
void PlatformView::NotifyCreated() {
  auto* platform_view = this;
  fml::ManualResetWaitableEvent latch;
  fml::TaskRunner::RunNowOrPostTask(
      task_runners_.GetGPUTaskRunner(), [platform_view, &surface, &latch]() {
        surface = platform_view->CreateRenderingSurface();
        latch.Signal();
      });
  latch.Wait();
  delegate_.OnPlatformViewCreated(std::move(surface));
}

這個delegate_其實是Shell涯贞,在AndroidShellHolder的構(gòu)造函數(shù)里面可以得知,看看這個OnPlatformViewCreated方法:

void Shell::OnPlatformViewCreated(std::unique_ptr<Surface> surface) {
    auto ui_task = [engine = engine_->GetWeakPtr(), //
        gpu_task_runner = task_runners_.GetGPUTaskRunner(),  //
        gpu_task, 
        should_post_gpu_task,
        &latch  //
    ] {
        if (engine) {
            engine->OnOutputSurfaceCreated();
        }
    }
    auto io_task = [io_manager = io_manager_->GetWeakPtr(), 
        platform_view,
        ui_task_runner = task_runners_.GetUITaskRunner(),
        ui_task
    ] {
        if (io_manager && !io_manager->GetResourceContext()) {
            io_manager->NotifyResourceContextAvailabl (platform_view->CreateResourceContext());
        }
        // Step 1: Next, post a task on the UI thread to tell the engine that it has
        // an output surface.
        fml::TaskRunner::RunNowOrPostTask(ui_task_runner, ui_task);
    };

    fml::TaskRunner::RunNowOrPostTask(task_runners_.GetIOTaskRunner(), io_task);
}

這里主要是檢查資源危喉,以及通知engine可以渲染并輸出surface了宋渔。

3、啟動

3.1 啟動flash頁面

FlutterView創(chuàng)建成功之后辜限,就開始對lauch頁做處理了皇拣,就是所說的應(yīng)用啟動開屏第一頁。先看看有沒有定義launchView列粪,在方法createLaunchView中:

private View createLaunchView() {
    if (!showSplashScreenUntilFirstFrame()) {
        return null;
    }
    final Drawable launchScreenDrawable = getLaunchScreenDrawableFromActivityTheme();
    if (launchScreenDrawable == null) {
        return null;
    }
    final View view = new View(activity);
    view.setLayoutParams(matchParent);
    view.setBackground(launchScreenDrawable);
    return view;
}

showSplashScreenUntilFirstFrame函數(shù)先判斷第一頁的標(biāo)志位是否打開:

private Boolean showSplashScreenUntilFirstFrame() {
    try {
        ActivityInfo activityInfo = activity.getPackageManager().getActivityInfo(
            activity.getComponentName(),
            PackageManager.GET_META_DATA|PackageManager.GET_ACTIVITIES);
        Bundle metadata = activityInfo.metaData;
        return metadata != null && metadata.getBoolean("io.flutter.app.android.SplashScreenUntilFirstFrame");
    } catch (NameNotFoundException e) {
        return false;
    }
}

也就是說看看當(dāng)前的Activity在AndroidManifest.xml里面定義的時候审磁,是否定義了這個key = io.flutter.app.android.SplashScreenUntilFirstFrame的metadata谈飒,并返回他配置的值,默認(rèn)返回false态蒂『即耄基于這個判斷,如果返回true钾恢,就進(jìn)行下一步手素,否則返回空。

看看下一步怎么獲取第一幀的資源:

private Drawable getLaunchScreenDrawableFromActivityTheme() {
    TypedValue typedValue = new TypedValue();
    if (!activity.getTheme().resolveAttribute(
        android.R.attr.windowBackground,
        typedValue,
        true)) {
        return null;
    }
    if (typedValue.resourceId == 0) {
        return null;
    }
    try {
        return activity.getResources().getDrawable(typedValue.resourceId);
    } catch (NotFoundException e) {
        Log.e(TAG, "Referenced launch screen windowBackground resource does not exist");
        return null;
    }
}

從這里看到瘩蚪,先判斷我們的Activity在AndroidManifest.xml里面定義的Theme泉懦,從這個theme里面獲取windowBackground標(biāo)簽的值給到typedValue。如果資源id有效疹瘦,就給到Drawable崩哩,返回Drawable對象。

最后把這個Drawable對象設(shè)置成View的背景返回就行了言沐。

lauchView不為空邓嘹,接下來addLaunchView:

private void addLaunchView() {
    if (launchView == null) {
        return;
    }

    activity.addContentView(launchView, matchParent);
    flutterView.addFirstFrameListener(new FlutterView.FirstFrameListener() {
        @Override
        public void onFirstFrame() {
            FlutterActivityDelegate.this.launchView.animate()
                .alpha(0f)
                .setListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        ((ViewGroup) FlutterActivityDelegate.this.launchView.getParent())
                            .removeView(FlutterActivityDelegate.this.launchView);
                        FlutterActivityDelegate.this.launchView = null;
                    }
                });

            FlutterActivityDelegate.this.flutterView.removeFirstFrameListener(this);
        }
    });
    activity.setTheme(android.R.style.Theme_Black_NoTitleBar);
}

先將launchView添加到最頂層,然后設(shè)置第一幀的監(jiān)聽险胰,當(dāng)?shù)谝粠秩就戤呏笮谘海蛯aunchView做一個透明度的動畫,動畫執(zhí)行完畢之后起便,將launchView移除棚贾,并移除第一幀的監(jiān)聽。

3.2 啟動dart代碼

加下來就會運行runBundle函數(shù):

/io/flutter/app/FlutterActivityDelegate.java

public void onCreate(Bundle savedInstanceState) {
    String appBundlePath = FlutterMain.findAppBundlePath();
    if (appBundlePath != null) {
        runBundle(appBundlePath);
    }
}

private void runBundle(String appBundlePath) {
    if (!flutterView.getFlutterNativeView().isApplicationRunning()) {
        FlutterRunArguments args = new FlutterRunArguments();
        args.bundlePath = appBundlePath;
        args.entrypoint = "main";
        flutterView.runFromBundle(args);
    }
}

appBundlePath對應(yīng)的flutter_assets榆综,entrypoint對應(yīng)的入口名稱妙痹,就是main.dart。

看看runFromBundle函數(shù)最終調(diào)用到了哪里:

io\flutter\view\FlutterNativeView.java

    public void runFromBundle(FlutterRunArguments args) {
    mFlutterJNI.runBundleAndSnapshotFromLibrary(
        args.bundlePath,
        args.entrypoint,
        args.libraryPath,
        mContext.getResources().getAssets()
    );

    applicationIsRunning = true;
}

到這里就通過FlutterJNI調(diào)用到了runBundleAndSnapshotFromLibrary:

io\flutter\embedding\engine\FlutterJNI.java

public void runBundleAndSnapshotFromLibrary(
      @NonNull String bundlePath,
      @Nullable String entrypointFunctionName,
      @Nullable String pathToEntrypointFunction,
      @NonNull AssetManager assetManager
  ) {
    nativeRunBundleAndSnapshotFromLibrary(
        nativePlatformViewId,
        bundlePath,
        entrypointFunctionName,
        pathToEntrypointFunction,
        assetManager
    );
}

最終到了native層:

shell\platform\android\platform_view_android_jni.cc

static void RunBundleAndSnapshotFromLibrary(){
    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() > 0) && (libraryUrl.size() > 0)) {
            config.SetEntrypointAndLibrary(std::move(entrypoint), std::move(libraryUrl));
        } else if (entrypoint.size() > 0) {
            config.SetEntrypoint(std::move(entrypoint));
        }
    }

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

看看Launch函數(shù):

shell\platform\android\android_shell_holder.cc

void AndroidShellHolder::Launch(RunConfiguration config) {
  shell_->RunEngine(std::move(config));
}

最終調(diào)用的地方在Shell.cc里面:

shell\common\shell.cc

void Shell::RunEngine(){
    fml::TaskRunner::RunNowOrPostTask(
    task_runners_.GetUITaskRunner(),
    fml::MakeCopyable(
      [run_configuration = std::move(run_configuration),
       weak_engine = weak_engine_, result]() mutable {
        auto run_result = weak_engine->Run(std::move(run_configuration));
        result(run_result);
    }));
}

到這里奖年,可以看到要啟動引擎了:

shell\common\engine.cc

Engine::RunStatus Engine::Run(RunConfiguration configuration) {
    auto isolate_launch_status = PrepareAndLaunchIsolate(std::move(configuration));
    std::shared_ptr<DartIsolate> isolate = runtime_controller_->GetRootIsolate().lock();
    bool isolate_running = isolate && isolate->GetPhase() == DartIsolate::Phase::Running;
    return isolate_running ? Engine::RunStatus::Success : Engine::RunStatus::Failure;
}

之前有說過根isolate的啟動细诸,是在engine啟動的時候才開始啟動沛贪,現(xiàn)在看看怎么啟動isolate的:

shell\common\engine.cc

Engine::RunStatus Engine::PrepareAndLaunchIsolate(){
    std::shared_ptr<DartIsolate> isolate = runtime_controller_->GetRootIsolate().lock();
    if (!isolate_configuration->PrepareIsolate(*isolate)) {
        return RunStatus::Failure;
    }
    if (!isolate->RunFromLibrary(configuration.GetEntrypointLibrary(), configuration.GetEntrypoint(), settings_.dart_entrypoint_args)) {
        FML_LOG(ERROR) << "Could not run the isolate.";
        return RunStatus::Failure;
    }
    return RunStatus::Success;
}

先獲取isolate對象陋守,然后運行RunFromLibrary方法:

runtime\dart_isolate.cc

[[nodiscard]] bool DartIsolate::RunFromLibrary(){
    auto user_entrypoint_function = Dart_GetField(Dart_LookupLibrary(tonic::ToDart(library_name.c_str())), tonic::ToDart(entrypoint_name.c_str()));
    auto entrypoint_args = tonic::ToDart(args);
    if (!InvokeMainEntrypoint(user_entrypoint_function, entrypoint_args)) {
        return false;
    }
    phase_ = Phase::Running;
    if (on_run) {
        on_run();
    }
    return true;
}

Dart_GetField的目的是在我們的dart代碼中目錄lib中查找main.dart文件,然后調(diào)用InvokeMainEntrypoint函數(shù)執(zhí)行里面的main方法:

runtime\dart_isolate.cc

[[nodiscard]] static bool InvokeMainEntrypoint(){
    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}))) {
        return false;
    }
    return true;
}

看看_runMainZoned方法:

lib\ui\hooks.dart

void _runMainZoned(Function startMainIsolateFunction,
                   Function userMainFunction,
                   List<String> args) {
    startMainIsolateFunction((){
        runZonedGuarded<void>(() {
            userMainFunction();
        }, (Object error, StackTrace stackTrace) {
        });
  }, null);    
}

最終調(diào)用的還是用戶的main函數(shù)利赋,就是我們一開始傳遞過去entrypoint值水评。

4、Isolate

看看DartIsolate這個類的注釋:

他代表了一個活著的isolate示例媚送。一個isolate是一個獨立的Dart可執(zhí)行上下文中燥。不同的isolate不共享內(nèi)存,并能夠被Dart VM虛擬機管理的工作線程池中的某一個Dart VM虛擬機同時調(diào)度塘偎。

Dart VM虛擬機控制著Dart isolate的整個生命周期疗涉,正因為如此拿霉,引擎從來不會在一段很長的時間段內(nèi)持有Dart VM虛擬機的強指針,這樣就允許Dart VM虛擬機或isolate本身去中斷Dart的執(zhí)行但并不影響引擎運行咱扣。

那些引擎創(chuàng)建的isolate看起來像是代表了UI綁定的Flutter應(yīng)用程序代碼被稱作底層(root)isolate绽淘。

根isolate有以下特性:

  • 根isolate創(chuàng)建了一個新的isolate組,子isolate被添加到這個組里面闹伪,當(dāng)根isolate死了沪铭,那么組里面所有的子isolate將會被中斷。
  • 只有根isolate能夠獲取UI綁定
  • 根isolate在引擎管理的線程上執(zhí)行他們的代碼偏瓤,而其他的isolate則在引擎無法控制的被Dart VM虛擬機管理的工作線程池上運行他們的Dart代碼
  • 正因為引擎不知道非根isolate運行在哪個線程杀怠,所以引擎也沒有機會去獲取一個非根部isolate的引用,而這些非根isolate只能被他們自己中斷或當(dāng)他們的isolate組被銷毀的時候而中斷厅克。

下面看看native層的調(diào)用流程圖:

圖片原地址:https://ftp.bmp.ovh/imgs/2020/04/baef9752ad881735.jpg

image

再看看Engine,Dart VM,Isolate之間的關(guān)系:

原圖片地址https://ftp.bmp.ovh/imgs/2020/04/9c7add234ca0464b.jpg

image

Shell從四個Thread中獲取到了四個Thread對應(yīng)的TaskRunner赔退,而TaskRunner中實際上是MessageLoopImpl在干活,從消息隊列中取出消息處理证舟。

https://github.com/flutter/flutter/wiki/The-Engine-architecture

比較特殊的是离钝,Engine是在UI TaskRunner里面新建并運行,在創(chuàng)建的過程中一并創(chuàng)建了Dart VM和Root Isolate褪储,我們上層寫的dart代碼也是運行在這個TaskRunner里面卵渴。不同的是,當(dāng)傳遞圖片到GPU鲤竹,畫面幀渲染的時候使用的是GPU TaskRunner,而一些IO操作比如從assets里面讀取文件等則是在IO TaskRunner里面去執(zhí)行浪读。IO與GPU交互頻繁,為了性能辛藻,IO TaskRunner 設(shè)置了一個特殊的上下文在一個相同的共享組里面碘橘,并將他作為GPU TaskRunner的主要上下文。

上述這些操作都是通過DartVM調(diào)度Isolate去實現(xiàn)的吱肌,目前Google在Android平臺上TaskRunner的策略是痘拆,一個Engine實例創(chuàng)建一個UI TaskRunner,一個IO TaskRunner氮墨,一個GPU TaskRunner纺蛆,所有的Engine實例共享一個Platform TaskRunner和他的Thread。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末规揪,一起剝皮案震驚了整個濱河市桥氏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌猛铅,老刑警劉巖字支,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡堕伪,警方通過查閱死者的電腦和手機揖庄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來欠雌,“玉大人抠艾,你說我怎么就攤上這事〗瓣迹” “怎么了检号?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蛙酪。 經(jīng)常有香客問我齐苛,道長,這世上最難降的妖魔是什么桂塞? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任凹蜂,我火速辦了婚禮,結(jié)果婚禮上阁危,老公的妹妹穿的比我還像新娘玛痊。我一直安慰自己,他們只是感情好狂打,可當(dāng)我...
    茶點故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布擂煞。 她就那樣靜靜地躺著,像睡著了一般趴乡。 火紅的嫁衣襯著肌膚如雪对省。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天晾捏,我揣著相機與錄音蒿涎,去河邊找鬼。 笑死惦辛,一個胖子當(dāng)著我的面吹牛劳秋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播胖齐,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼玻淑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了市怎?” 一聲冷哼從身側(cè)響起岁忘,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤辛慰,失蹤者是張志新(化名)和其女友劉穎区匠,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡驰弄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年麻汰,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片戚篙。...
    茶點故事閱讀 40,438評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡五鲫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出岔擂,到底是詐尸還是另有隱情位喂,我是刑警寧澤,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布乱灵,位于F島的核電站塑崖,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏痛倚。R本人自食惡果不足惜规婆,卻給世界環(huán)境...
    茶點故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蝉稳。 院中可真熱鬧抒蚜,春花似錦、人聲如沸耘戚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽收津。三九已至器贩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間朋截,已是汗流浹背蛹稍。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留部服,地道東北人唆姐。 一個月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像廓八,于是被迫代替她去往敵國和親奉芦。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,446評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 今天基于Android分析下Flutter的啟動流程剧蹂,首先看下官網(wǎng)提供的框架圖声功,最下面一層Embedder是特定的...
    juexingzhe閱讀 2,131評論 1 4
  • 版權(quán)聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議宠叼,轉(zhuǎn)載請附上原文出處鏈接和本聲明先巴。本文鏈接:...
    上山砍柴閱讀 2,575評論 0 3
  • 先從一張架構(gòu)預(yù)覽圖說起吧: Framework Framework層是純dart語言寫的其爵,它實現(xiàn)了一套用于處理An...
    埃賽爾閱讀 1,957評論 0 3
  • 昨日回憶:昨天晚上很晚才到廈門,去到民宿真的有點失望伸蚯,下次還是正常選個酒店吧摩渺。棟哥說要來陪我,但我堅定拒絕了剂邮,其實...
    陪著你1949閱讀 67評論 0 1
  • 按圖索驥摇幻。PHP中使用最為頻繁的數(shù)據(jù)類型非字符串和數(shù)組莫屬,PHP比較容易上手也得益于非常靈活的數(shù)組類型挥萌。 在開始...
    拉風(fēng)的老衲閱讀 736評論 0 3