Flutter Engine

7-12 6,041 views

Getting Source code

Install depot_tools

Clone the depot_tools repository:

$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git

Add depot_tools to the end of your PATH (you will probably want to put this in your ~/.bashrc or ~/.zshrc). Assuming you cloned depot_tools to /path/to/depot_tools:

export PATH=`pwd`/depot_tools:$PATH

Set Proxy

export http_proxy=http://127.0.0.1:4000
export https_proxy=https://127.0.0.1:4000

Getting the code

  • Create an empty directory for your copy of the repository. For best results, call it engine: some of the tools assume this name when working across repositories. (They can be configured to use other names too, so this isn't a strict requirement.)
  • Create a .gclient file in the engine directory with the following contents, replacing <your_name_here> with your GitHub account name:
solutions = [
  {
    "managed": False,
    "name": "src/flutter",
    "url": "https://github.com/flutter/engine.git",
    "custom_deps": {},
    "deps_file": "DEPS",
    "safesync_url": "",
  },
]
  • cd engine (Change to the directory in which you put the .gclient file.)
  • gclient sync This will fetch all the source code that Flutter depends on. Avoid interrupting this script, it can leave your repository in an inconsistent state that is tedious to clean up.
  • cd src/flutter (Change to the flutter directory of the src directory that gclient sync created in your engine directory.)
  • git remote add upstream git@github.com:flutter/engine.git (So that you fetch from the master flutter/engine repository, not your clone, when running git fetch et al.)
  • cd .. (Return to the src directory that gclient sync created in your engine directory.)
  • If you're on Linux, run sudo ./build/install-build-deps-android.sh
  • If you're on Linux, run sudo ./build/install-build-deps.sh
  • If you're on Mac, install Oracle's Java JDK, version 1.7 or later.
  • If you're on Mac, install ant: brew install ant
  • If you're on Windows, install Visual Studio (non-Google developers only)
  • If you're planning on working on the buildroot repository as well, and have a local checkout of that repository, run the following commands in the src directory to update your git remotes accordingly:
git remote rename origin upstream
git remote add origin git@github.com:<your_name_here>/buildroot.git

Android

FlutterApplication

Flutter的大致原理是在Application的入口函数 onCreate 通过 System.loadLibrary("flutter") 加载 FlutterEngine 库来实现

首先将源码定位到 engine/shell/platform/android/io/flutter/app/FlutterApplication.java

public class FlutterApplication extends Application {
    @Override
    @CallSuper
    public void onCreate() {
        super.onCreate();
        FlutterMain.startInitialization(this);   // 1️⃣
    }
    ...
}

engine/shell/platform/android/io/flutter/view/FlutterMain.java

public static void startInitialization(Context applicationContext, Settings settings) {
    ...

    initConfig(applicationContext);
    initAot(applicationContext);
    initResources(applicationContext);
    System.loadLibrary("flutter");    // 2️⃣
    ...
}

FlutterActivity

engine/shell/platform/android/io/flutter/app/FlutterActivity.java

public class FlutterActivity extends Activity implements FlutterView.Provider, PluginRegistry, ViewFactory {
    private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this);

    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        eventDelegate.onCreate(savedInstanceState);
    }
}

engine/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java

public final class FlutterActivityDelegate
        implements FlutterActivityEvents,
                   FlutterView.Provider,
                   PluginRegistry {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        //  3️⃣
        FlutterMain.ensureInitializationComplete(activity.getApplicationContext(), args);

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

        // When an activity is created for the first time, we direct the
        // FlutterView to re-use a pre-existing Isolate rather than create a new
        // one. This is so that an Isolate coming in from the ViewFactory is
        // used.
        final boolean reuseIsolate = true;

        if (loadIntent(activity.getIntent(), reuseIsolate)) {
            return;
        }
        if (!flutterView.getFlutterNativeView().isApplicationRunning()) {
          String appBundlePath = FlutterMain.findAppBundlePath(activity.getApplicationContext());
          if (appBundlePath != null) {
            flutterView.runFromBundle(appBundlePath, null, "main", reuseIsolate);
          }
        }
    }

}

engine/shell/platform/android/io/flutter/app/FlutterMain.java

public static void ensureInitializationComplete(Context applicationContext, String[] args) {
    ...
                nativeInit(applicationContext, shellArgs.toArray(new String[0]),   // 5️⃣
                appBundlePath);
    ...
}

nativeInit 对应 FlutterMain::Init

engine/shell/platform/android/flutter_main.cc

void FlutterMain::Init(JNIEnv* env,
                       jclass clazz,
                       jobject context,
                       jobjectArray jargs,
                       jstring bundlePath) {
  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 = fxl::CommandLineFromIterators(args.begin(), args.end());

  auto settings = SettingsFromCommandLine(command_line);

  settings.assets_path = fml::jni::JavaStringToString(env, bundlePath);

  // 6️⃣
  if (!blink::DartVM::IsRunningPrecompiledCode()) {
    // Check to see if the appropriate kernel files are present and configure
    // settings accordingly.
    auto platform_kernel_path =
        fml::paths::JoinPaths({settings.assets_path, "platform.dill"});
    auto application_kernel_path =
        fml::paths::JoinPaths({settings.assets_path, "kernel_blob.bin"});

    if (files::IsFile(application_kernel_path)) {
      settings.application_kernel_asset = application_kernel_path;
      if (files::IsFile(platform_kernel_path)) {
        settings.platform_kernel_path = platform_kernel_path;
      }
    }
  }

  settings.task_observer_add = [](intptr_t key, fxl::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)));
}

AndroidSurface

engine/shell/platform/android/io/flutter/view/FlutterView.java

public FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) {
    ......

    Activity activity = (Activity) getContext();
    // 1️⃣
    if (nativeView == null) {
        mNativeView = new FlutterNativeView(activity.getApplicationContext());
    } else {
        mNativeView = nativeView;
    }
    mNativeView.attachViewAndActivity(this, activity);

    ......

    mSurfaceCallback = new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            assertAttached();
            // 2️⃣
            nativeSurfaceCreated(mNativeView.get(), holder.getSurface(), backgroundColor);
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            assertAttached();
            nativeSurfaceChanged(mNativeView.get(), width, height);
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            assertAttached();
            nativeSurfaceDestroyed(mNativeView.get());
        }
    };
    getHolder().addCallback(mSurfaceCallback);

    ......
}

先看 1️⃣ 处代码 FlutterNativeView

engine/shell/platform/android/io/flutter/view/FlutterNativeView.java

    public FlutterNativeView(Context context) {
        mContext = context;
        mPluginRegistry = new FlutterPluginRegistry(this, context);
        attach(this);  // 3️⃣
        assertAttached();
        mMessageHandlers = new HashMap<>();
    }

attach 方法调用了 nativeAttach 方法,在其内部创建 AndroidSurface

    private void attach(FlutterNativeView view) {
        mNativePlatformView = nativeAttach(view);
    }

engine/shell/platform/android/platform_view_android_jni.cc

// Called By Java
static jlong Attach(JNIEnv* env, jclass clazz, jobject flutterView) {
  fml::jni::JavaObjectWeakGlobalRef java_object(env, flutterView);
  auto shell_holder = std::make_unique<AndroidShellHolder>(  // 4️⃣ 创建 AndroidShellHolder
      FlutterMain::Get().GetSettings(), java_object);
  if (shell_holder->IsValid()) {
    return reinterpret_cast<jlong>(shell_holder.release());
  } else {
    return 0;
  }
}

engine/shell/platform/android/android_shell_holder.cc

AndroidShellHolder::AndroidShellHolder(
    blink::Settings settings,
    fml::jni::JavaObjectWeakGlobalRef java_object)
    : settings_(std::move(settings)), java_object_(java_object) {
    ......
      fml::WeakPtr<PlatformViewAndroid> weak_platform_view;
      Shell::CreateCallback<PlatformView> on_create_platform_view =
          [java_object, &weak_platform_view](Shell& shell) {
          // 5️⃣ 创建 PlatformViewAndroid
            auto 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;
          };
    ......
}

engine/shell/platform/android/platform_view_android.cc

PlatformViewAndroid::PlatformViewAndroid(
    PlatformView::Delegate& delegate,
    blink::TaskRunners task_runners,
    fml::jni::JavaObjectWeakGlobalRef java_object,
    bool use_software_rendering)
    : PlatformView(delegate, std::move(task_runners)),
      java_object_(java_object),
      // 6️⃣ 创建 AndroidSurface
      android_surface_(AndroidSurface::Create(use_software_rendering)) {
  FXL_CHECK(android_surface_)
      << "Could not create an OpenGL, Vulkan or Software surface to setup "
         "rendering.";
}

AndroidSurface 有三中实现 AndroidSurfaceSoftwareAndroidSurfaceVulkanAndroidSurfaceGL

engine/shell/platform/android/android_surface.cc

std::unique_ptr<AndroidSurface> AndroidSurface::Create(
    bool use_software_rendering) {
  if (use_software_rendering) {
    auto software_surface = std::make_unique<AndroidSurfaceSoftware>();
    return software_surface->IsValid() ? std::move(software_surface) : nullptr;
  }
#if SHELL_ENABLE_VULKAN
  auto vulkan_surface = std::make_unique<AndroidSurfaceVulkan>();
  return vulkan_surface->IsValid() ? std::move(vulkan_surface) : nullptr;
#else   // SHELL_ENABLE_VULKAN
  auto gl_surface = std::make_unique<AndroidSurfaceGL>();
  return gl_surface->IsOffscreenContextValid() ? std::move(gl_surface)
                                               : nullptr;
#endif  // SHELL_ENABLE_VULKAN
}

再看 FlutterView 2️⃣ 处的代码

engine/shell/platform/android/platform_view_android_jni.cc

  static const JNINativeMethod view_methods[] = {
      {
          .name = "nativeSurfaceCreated",
          .signature = "(JLandroid/view/Surface;I)V",
          .fnPtr = reinterpret_cast<void*>(&shell::SurfaceCreated),
      },
      ......
  }

定位到 SurfaceCreated 方法:

engine/shell/platform/android/platform_view_android_jni.cc

static void SurfaceCreated(JNIEnv* env,
                           jobject jcaller,
                           jlong shell_holder,
                           jobject jsurface,
                           jint backgroundColor) {
  // Note: This frame ensures that any local references used by
  // ANativeWindow_fromSurface are released immediately. This is needed as a
  // workaround for https://code.google.com/p/android/issues/detail?id=68174
  fml::jni::ScopedJavaLocalFrame scoped_local_reference_frame(env);
  auto window = fxl::MakeRefCounted<AndroidNativeWindow>(
      ANativeWindow_fromSurface(env, jsurface));
    // 7️⃣
  ANDROID_SHELL_HOLDER->GetPlatformView()->NotifyCreated(std::move(window));
}

engine/shell/platform/android/platform_view_android.cc

void PlatformViewAndroid::NotifyCreated(
    fxl::RefPtr<AndroidNativeWindow> native_window) {
  InstallFirstFrameCallback();
    // 8️⃣
  android_surface_->SetNativeWindow(native_window);
    // 9️⃣
  PlatformView::NotifyCreated();
}

先看 8️⃣ 处的代码,由于 AndroidSurface 有三种实现,这里只看 android_surface_software

engine/shell/platform/android/android_surface_software.cc

bool AndroidSurfaceSoftware::SetNativeWindow(
    fxl::RefPtr<AndroidNativeWindow> window) {
  native_window_ = std::move(window);
  if (!(native_window_ && native_window_->IsValid()))
    return false;
  int32_t window_format = ANativeWindow_getFormat(native_window_->handle());
  if (window_format < 0)
    return false;
  if (!GetSkColorType(window_format, &target_color_type_, &target_alpha_type_))
    return false;
  return true;
}

接着继续看 9️⃣ 的代码:

engine/shell/common/platform_view.cc

void PlatformView::NotifyCreated() {
  delegate_.OnPlatformViewCreated(*this, CreateRenderingSurface());
}

delegate_ 的值为:

engine/shell/common/shell.cc

// |shell::PlatformView::Delegate|
void Shell::OnPlatformViewCreated(const PlatformView& view,
                                  std::unique_ptr<Surface> surface) {
  FXL_DCHECK(is_setup_);
  FXL_DCHECK(&view == platform_view_.get());
  FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());

  // Note:
  // This is a synchronous operation because certain platforms depend on
  // setup/suspension of all activities that may be interacting with the GPU in
  // a synchronous fashion.

  fxl::AutoResetWaitableEvent latch;
  auto gpu_task = fxl::MakeCopyable([rasterizer = rasterizer_->GetWeakPtr(),  //
                                     surface = std::move(surface),            //
                                     &latch]() mutable {
    if (rasterizer) {
      rasterizer->Setup(std::move(surface));
    }
    // Step 2: All done. Signal the latch that the platform thread is waiting
    // on.
    latch.Signal();
  });

  auto ui_task = [engine = engine_->GetWeakPtr(),                      //
                  gpu_task_runner = task_runners_.GetGPUTaskRunner(),  //
                  gpu_task                                             //
  ] {
    if (engine) {
        // ?
      engine->OnOutputSurfaceCreated();
    }
    // Step 1: Next, tell the GPU thread that it should create a surface for its
    // rasterizer.
    fml::TaskRunner::RunNowOrPostTask(gpu_task_runner, gpu_task);
  };

  // Step 0: Post a task onto the UI thread to tell the engine that it has an
  // output surface.
  fml::TaskRunner::RunNowOrPostTask(task_runners_.GetUITaskRunner(), ui_task);
  latch.Wait();
}

engine/shell/common/engine.cc

void Engine::OnOutputSurfaceCreated() {
  have_surface_ = true;
  StartAnimatorIfPossible();
  ScheduleFrame();
}

engine/shell/common/rasterizer.cc

void Rasterizer::Setup(std::unique_ptr<Surface> surface) {
  surface_ = std::move(surface);
  compositor_context_->OnGrContextCreated();
}

Canvas

engine/lib/ui/painting/canvas.cc

engine/lib/ui/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);
    ...
    Window::RegisterNatives(g_natives);
  }
}

engine/lib/ui/painting.dart

包名:

part of dart.ui;

Canvas

class Canvas extends NativeFieldWrapperClass2 {
  Canvas(PictureRecorder recorder, [ Rect cullRect ]) : assert(recorder != null) {
    if (recorder.isRecording)
      throw new ArgumentError('"recorder" must not already be associated with another Canvas.');
    cullRect ??= Rect.largest;
    _constructor(recorder, cullRect.left, cullRect.top, cullRect.right, cullRect.bottom);
  }
  void _constructor(PictureRecorder recorder,
                    double left,
                    double top,
                    double right,
                    double bottom) native 'Canvas_constructor';

  void save() native 'Canvas_save';

  ...
}

类似 Java 的 native 方法,dart native extensions

static void Canvas_constructor(Dart_NativeArguments args) {
  DartCallConstructor(&Canvas::Create, args);
}
void Canvas::RegisterNatives(tonic::DartLibraryNatives* natives) {
  natives->Register({{"Canvas_constructor", Canvas_constructor, 6, true},
                     FOR_EACH_BINDING(DART_REGISTER_NATIVE)});
}

fxl::RefPtr<Canvas> Canvas::Create(PictureRecorder* recorder,
                                   double left,
                                   double top,
                                   double right,
                                   double bottom) {
  if (!recorder)
    Dart_ThrowException(
        ToDart("Canvas constructor called with non-genuine PictureRecorder."));
  FXL_DCHECK(!recorder->isRecording());  // verified by Dart code
  fxl::RefPtr<Canvas> canvas = fxl::MakeRefCounted<Canvas>(
      recorder->BeginRecording(SkRect::MakeLTRB(left, top, right, bottom)));
  recorder->set_canvas(canvas);
  return canvas;
}

flutter/packages/flutter/lib/src/rendering/object.dart

  /// The canvas on which to paint.
  ///
  /// The current canvas can change whenever you paint a child using this
  /// context, which means it's fragile to hold a reference to the canvas
  /// returned by this getter.
  Canvas get canvas {
    if (_canvas == null)
      _startRecording();
    return _canvas;
  }

  void _startRecording() {
    assert(!_isRecording);
    _currentLayer = new PictureLayer(estimatedBounds);
    _recorder = new ui.PictureRecorder();
    _canvas = new Canvas(_recorder);
    _containerLayer.append(_currentLayer);
  }

FlutterEngineRun

engine/shell/platform/embedder/embedder.cc

FlutterResult FlutterEngineRun(size_t version,
                               const FlutterRendererConfig* config,
                               const FlutterProjectArgs* args,
                               void* user_data,
                               FlutterEngine* engine_out) {
  ......
  // Step 1: Create the engine.
  auto embedder_engine =
      std::make_unique<shell::EmbedderEngine>(std::move(thread_host),   //
                                              std::move(task_runners),  //
                                              settings,                 //
                                              on_create_platform_view,  //
                                              on_create_rasterizer      //
      );

  if (!embedder_engine->IsValid()) {
    return kInvalidArguments;
  }

  // Step 2: Setup the rendering surface.
  if (!embedder_engine->NotifyCreated()) {
    return kInvalidArguments;
  }

  // Step 3: Run the engine.
  auto run_configuration = shell::RunConfiguration::InferFromSettings(settings);

  run_configuration.AddAssetResolver(
      std::make_unique<blink::DirectoryAssetBundle>(
          fml::Duplicate(settings.assets_dir)));

  run_configuration.AddAssetResolver(
      std::make_unique<blink::DirectoryAssetBundle>(fml::OpenFile(
          settings.assets_path.c_str(), fml::OpenPermission::kRead, true)));

  if (!embedder_engine->Run(std::move(run_configuration))) {
    return kInvalidArguments;
  }

  // Finally! Release the ownership of the embedder engine to the caller.
  *engine_out = reinterpret_cast<FlutterEngine>(embedder_engine.release());
  return kSuccess;
}

16 条评论

  1. I loved as much as you will receive carried out right here.

    The sketch is attractive, your authored subject matter stylish.
    nonetheless, you command get bought an nervousness over that you wish be delivering the following.

    unwell unquestionably come more formerly again as exactly the same nearly a lot often inside case you shield this hike. http://alternatif188bet.com

  2. I loved as much as you will receive carried out right here.
    The sketch is attractive, your authored subject matter stylish.
    nonetheless, you command get bought an nervousness over that you wish be delivering the following.
    unwell unquestionably come more formerly again as exactly
    the same nearly a lot often inside case you shield this hike. http://alternatif188bet.com

欢迎留言