未验证 提交 903ef089 编写于 作者: S stuartmorgan 提交者: GitHub

Support AOT mode for Windows (#18589)

- Adds a way to provide an AOT library to the C API.
- Adds app.so to the information provided by DartProject.
- Fixes the engine to only do static snapshot linking for Windows in
  debug mode, not all modes, so that the provided library is used.

Engine side of https://github.com/flutter/flutter/issues/38477
上级 1a834988
......@@ -89,28 +89,6 @@ source_set("runtime") {
"//third_party/skia",
]
# On Windows the engine finds the Dart snapshot data through symbols
# that are statically linked into the executable. On other platforms this
# data is obtained by a dynamic symbol lookup.
# The current Windows platform uses static-link instead of dynamic lookups.
# Because:
# 1. The size of the executable on Windows is not as concerned as on mobile
# platforms.
# 2. If it is a dynamic lookup method, you need to modify the properties of
# the memory page after the *.bin is dynamically loaded at runtime and
# mark it as executable. This is feasible (similar to V8 on Windows), but
# this increases the complexity of the implementation(These operations
# involve the use of some system file/memory privilege APIs and there is
# a risk of failure).
# 3. In the executable can enjoy the advantages of the windows preload
# mechanism, speed up I/O.
if (is_win) {
if (flutter_runtime_mode == "profile" ||
flutter_runtime_mode == "release") {
deps += [ "//flutter/lib/snapshot" ]
}
}
public_deps = [
"//third_party/rapidjson",
]
......
......@@ -24,7 +24,7 @@ const char* DartSnapshot::kIsolateInstructionsSymbol =
// data through symbols that are statically linked into the executable.
// On other platforms this data is obtained by a dynamic symbol lookup.
#define DART_SNAPSHOT_STATIC_LINK \
(OS_WIN || (OS_ANDROID && FLUTTER_JIT_RUNTIME))
((OS_WIN || OS_ANDROID) && FLUTTER_JIT_RUNTIME)
#if !DART_SNAPSHOT_STATIC_LINK
......
......@@ -22,6 +22,11 @@ class DartProjectTest : public ::testing::Test {
return project.assets_path();
}
// Wrapper for accessing private aot_library_path_.
std::wstring GetProjectAotLibraryPath(const DartProject& project) {
return project.aot_library_path();
}
// Wrapper for accessing private engine_switches.
std::vector<std::string> GetProjectEngineSwitches(
const DartProject& project) {
......@@ -33,6 +38,7 @@ TEST_F(DartProjectTest, StandardProjectFormat) {
DartProject project(L"test");
EXPECT_EQ(GetProjectIcuDataPath(project), L"test\\icudtl.dat");
EXPECT_EQ(GetProjectAssetsPath(project), L"test\\flutter_assets");
EXPECT_EQ(GetProjectAotLibraryPath(project), L"test\\app.so");
}
TEST_F(DartProjectTest, Switches) {
......
......@@ -22,6 +22,8 @@ FlutterViewController::FlutterViewController(int width,
FlutterDesktopEngineProperties properties = {};
properties.assets_path = project.assets_path().c_str();
properties.icu_data_path = project.icu_data_path().c_str();
// It is harmless to pass this in non-AOT mode.
properties.aot_library_path = project.aot_library_path().c_str();
properties.switches = switch_count > 0 ? switches.data() : nullptr;
properties.switches_count = switch_count;
controller_ = FlutterDesktopCreateViewController(width, height, properties);
......
......@@ -17,12 +17,14 @@ class DartProject {
// the following top-level items:
// - icudtl.dat (provided as a resource by the Flutter tool)
// - flutter_assets (as built by the Flutter tool)
// - app.so, for an AOT build (as built by the Flutter tool)
//
// The path can either be absolute, or relative to the directory containing
// the running executable.
explicit DartProject(const std::wstring& path) {
assets_path_ = path + L"\\flutter_assets";
icu_data_path_ = path + L"\\icudtl.dat";
aot_library_path_ = path + L"\\app.so";
}
~DartProject() = default;
......@@ -48,6 +50,7 @@ class DartProject {
const std::wstring& assets_path() const { return assets_path_; }
const std::wstring& icu_data_path() const { return icu_data_path_; }
const std::wstring& aot_library_path() const { return aot_library_path_; }
const std::vector<std::string>& engine_switches() const {
return engine_switches_;
}
......@@ -56,6 +59,9 @@ class DartProject {
std::wstring assets_path_;
// The path to the ICU data.
std::wstring icu_data_path_;
// The path to the AOT library. This will always return a path, but non-AOT
// builds will not be expected to actually have a library at that path.
std::wstring aot_library_path_;
// Switches to pass to the engine.
std::vector<std::string> engine_switches_;
};
......
......@@ -12,6 +12,7 @@
#include <cstdlib>
#include <filesystem>
#include <iostream>
#include <memory>
#include <vector>
#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/plugin_registrar.h"
......@@ -29,6 +30,33 @@
static_assert(FLUTTER_ENGINE_VERSION == 1, "");
// Attempts to load AOT data from the given path, which must be absolute and
// non-empty. Logs and returns nullptr on failure.
UniqueAotDataPtr LoadAotData(std::filesystem::path aot_data_path) {
if (aot_data_path.empty()) {
std::cerr
<< "Attempted to load AOT data, but no aot_library_path was provided."
<< std::endl;
return nullptr;
}
if (!std::filesystem::exists(aot_data_path)) {
std::cerr << "Can't load AOT data from " << aot_data_path.u8string()
<< "; no such file." << std::endl;
return nullptr;
}
std::string path_string = aot_data_path.u8string();
FlutterEngineAOTDataSource source = {};
source.type = kFlutterEngineAOTDataSourceTypeElfPath;
source.elf_path = path_string.c_str();
FlutterEngineAOTData data = nullptr;
auto result = FlutterEngineCreateAOTData(&source, &data);
if (result != kSuccess) {
std::cerr << "Failed to load AOT data from: " << path_string << std::endl;
return nullptr;
}
return UniqueAotDataPtr(data);
}
// Spins up an instance of the Flutter Engine.
//
// This function launches the Flutter Engine in a background thread, supplying
......@@ -108,7 +136,12 @@ static std::unique_ptr<FlutterDesktopEngineState> RunFlutterEngine(
std::filesystem::path assets_path(engine_properties.assets_path);
std::filesystem::path icu_path(engine_properties.icu_data_path);
if (assets_path.is_relative() || icu_path.is_relative()) {
std::filesystem::path aot_library_path =
engine_properties.aot_library_path == nullptr
? std::filesystem::path()
: std::filesystem::path(engine_properties.aot_library_path);
if (assets_path.is_relative() || icu_path.is_relative() ||
(!aot_library_path.empty() && aot_library_path.is_relative())) {
// Treat relative paths as relative to the directory of this executable.
std::filesystem::path executable_location =
flutter::GetExecutableDirectory();
......@@ -120,10 +153,22 @@ static std::unique_ptr<FlutterDesktopEngineState> RunFlutterEngine(
}
assets_path = std::filesystem::path(executable_location) / assets_path;
icu_path = std::filesystem::path(executable_location) / icu_path;
if (!aot_library_path.empty()) {
aot_library_path =
std::filesystem::path(executable_location) / aot_library_path;
}
}
std::string assets_path_string = assets_path.u8string();
std::string icu_path_string = icu_path.u8string();
if (FlutterEngineRunsAOTCompiledDartCode()) {
state->aot_data = LoadAotData(aot_library_path);
if (!state->aot_data) {
std::cerr << "Unable to start engine without AOT data." << std::endl;
return nullptr;
}
}
FlutterProjectArgs args = {};
args.struct_size = sizeof(FlutterProjectArgs);
args.assets_path = assets_path_string.c_str();
......@@ -137,6 +182,9 @@ static std::unique_ptr<FlutterDesktopEngineState> RunFlutterEngine(
return window->HandlePlatformMessage(engine_message);
};
args.custom_task_runners = &custom_task_runners;
if (state->aot_data) {
args.aot_data = state->aot_data.get();
}
FLUTTER_API_SYMBOL(FlutterEngine) engine = nullptr;
auto result =
......
......@@ -5,6 +5,7 @@
#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_PUBLIC_FLUTTER_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_PUBLIC_FLUTTER_H_
#include <Windows.h>
#include <stddef.h>
#include <stdint.h>
......@@ -12,8 +13,6 @@
#include "flutter_messenger.h"
#include "flutter_plugin_registrar.h"
#include "Windows.h"
#if defined(__cplusplus)
extern "C" {
#endif
......@@ -40,6 +39,12 @@ typedef struct {
// containing the executable.
const wchar_t* icu_data_path;
// The path to the AOT libary file for your application, if any.
// This can either be an absolute path or a path relative to the directory
// containing the executable. This can be nullptr for a non-AOT build, as
// it will be ignored in that case.
const wchar_t* aot_library_path;
// The switches to pass to the Flutter engine.
//
// See: https://github.com/flutter/engine/blob/master/shell/common/switches.h
......
......@@ -39,6 +39,14 @@ struct FlutterDesktopView {
flutter::Win32FlutterWindow* window;
};
struct AotDataDeleter {
void operator()(FlutterEngineAOTData aot_data) {
FlutterEngineCollectAOTData(aot_data);
}
};
using UniqueAotDataPtr = std::unique_ptr<_FlutterEngineAOTData, AotDataDeleter>;
// Struct for storing state of a Flutter engine instance.
struct FlutterDesktopEngineState {
// The handle to the Flutter engine instance.
......@@ -46,6 +54,9 @@ struct FlutterDesktopEngineState {
// Task runner for tasks posted from the engine.
std::unique_ptr<flutter::Win32TaskRunner> task_runner;
// AOT data, if any.
UniqueAotDataPtr aot_data;
};
// State associated with the plugin registrar.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册