Skip to content

Commit d96f962

Browse files
Add new FlutterEngineAOTData argument to FlutterProjectArgs (flutter#18146)
Added a new `FlutterEngineAOTData` argument to `FlutterProjectArgs`. Embedders can instantiate and destroy this object via the new `FlutterEngineCreateAOTData` and `FlutterEngineCollectAOTData` methods provided. If an embedder provides more than one source of AOT data to `FlutterEngineInitialize` or `FlutterEngineRun` (e.g. snapshots as well as `FlutterEngineAOTData`), the engine will error out. Resolves: flutter#50778
1 parent 9913400 commit d96f962

File tree

10 files changed

+335
-6
lines changed

10 files changed

+335
-6
lines changed

shell/platform/embedder/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ template("embedder_source_set") {
7171
"//flutter/shell/common",
7272
"//flutter/third_party/tonic",
7373
"//third_party/dart/runtime/bin:dart_io_api",
74+
"//third_party/dart/runtime/bin:elf_loader",
7475
"//third_party/skia",
7576
]
7677

shell/platform/embedder/embedder.cc

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "flutter/fml/closure.h"
1212
#include "flutter/fml/make_copyable.h"
1313
#include "flutter/fml/native_library.h"
14+
#include "third_party/dart/runtime/bin/elf_loader.h"
1415
#include "third_party/dart/runtime/include/dart_native_api.h"
1516

1617
#if OS_WIN
@@ -532,6 +533,83 @@ struct _FlutterPlatformMessageResponseHandle {
532533
fml::RefPtr<flutter::PlatformMessage> message;
533534
};
534535

536+
struct LoadedElfDeleter {
537+
void operator()(Dart_LoadedElf* elf) {
538+
if (elf) {
539+
::Dart_UnloadELF(elf);
540+
}
541+
}
542+
};
543+
544+
using UniqueLoadedElf = std::unique_ptr<Dart_LoadedElf, LoadedElfDeleter>;
545+
546+
struct _FlutterEngineAOTData {
547+
UniqueLoadedElf loaded_elf = nullptr;
548+
const uint8_t* vm_snapshot_data = nullptr;
549+
const uint8_t* vm_snapshot_instrs = nullptr;
550+
const uint8_t* vm_isolate_data = nullptr;
551+
const uint8_t* vm_isolate_instrs = nullptr;
552+
};
553+
554+
FlutterEngineResult FlutterEngineCreateAOTData(
555+
const FlutterEngineAOTDataSource* source,
556+
FlutterEngineAOTData* data_out) {
557+
if (!flutter::DartVM::IsRunningPrecompiledCode()) {
558+
return LOG_EMBEDDER_ERROR(kInvalidArguments,
559+
"AOT data can only be created in AOT mode.");
560+
} else if (!source) {
561+
return LOG_EMBEDDER_ERROR(kInvalidArguments, "Null source specified.");
562+
} else if (!data_out) {
563+
return LOG_EMBEDDER_ERROR(kInvalidArguments, "Null data_out specified.");
564+
}
565+
566+
switch (source->type) {
567+
case kFlutterEngineAOTDataSourceTypeElfPath: {
568+
if (!source->elf_path || !fml::IsFile(source->elf_path)) {
569+
return LOG_EMBEDDER_ERROR(kInvalidArguments,
570+
"Invalid ELF path specified.");
571+
}
572+
573+
auto aot_data = std::make_unique<_FlutterEngineAOTData>();
574+
const char* error = nullptr;
575+
576+
Dart_LoadedElf* loaded_elf = Dart_LoadELF(
577+
source->elf_path, // file path
578+
0, // file offset
579+
&error, // error (out)
580+
&aot_data->vm_snapshot_data, // vm snapshot data (out)
581+
&aot_data->vm_snapshot_instrs, // vm snapshot instr (out)
582+
&aot_data->vm_isolate_data, // vm isolate data (out)
583+
&aot_data->vm_isolate_instrs // vm isolate instr (out)
584+
);
585+
586+
if (loaded_elf == nullptr) {
587+
return LOG_EMBEDDER_ERROR(kInvalidArguments, error);
588+
}
589+
590+
aot_data->loaded_elf.reset(loaded_elf);
591+
592+
*data_out = aot_data.release();
593+
return kSuccess;
594+
}
595+
}
596+
597+
return LOG_EMBEDDER_ERROR(
598+
kInvalidArguments,
599+
"Invalid FlutterEngineAOTDataSourceType type specified.");
600+
}
601+
602+
FlutterEngineResult FlutterEngineCollectAOTData(FlutterEngineAOTData data) {
603+
if (data) {
604+
data->loaded_elf = nullptr;
605+
data->vm_snapshot_data = nullptr;
606+
data->vm_snapshot_instrs = nullptr;
607+
data->vm_isolate_data = nullptr;
608+
data->vm_isolate_instrs = nullptr;
609+
}
610+
return kSuccess;
611+
}
612+
535613
void PopulateSnapshotMappingCallbacks(const FlutterProjectArgs* args,
536614
flutter::Settings& settings) {
537615
// There are no ownership concerns here as all mappings are owned by the
@@ -543,6 +621,20 @@ void PopulateSnapshotMappingCallbacks(const FlutterProjectArgs* args,
543621
};
544622

545623
if (flutter::DartVM::IsRunningPrecompiledCode()) {
624+
if (SAFE_ACCESS(args, aot_data, nullptr) != nullptr) {
625+
settings.vm_snapshot_data =
626+
make_mapping_callback(args->aot_data->vm_snapshot_data, 0);
627+
628+
settings.vm_snapshot_instr =
629+
make_mapping_callback(args->aot_data->vm_snapshot_instrs, 0);
630+
631+
settings.isolate_snapshot_data =
632+
make_mapping_callback(args->aot_data->vm_isolate_data, 0);
633+
634+
settings.isolate_snapshot_instr =
635+
make_mapping_callback(args->aot_data->vm_isolate_instrs, 0);
636+
}
637+
546638
if (SAFE_ACCESS(args, vm_snapshot_data, nullptr) != nullptr) {
547639
settings.vm_snapshot_data = make_mapping_callback(
548640
args->vm_snapshot_data, SAFE_ACCESS(args, vm_snapshot_data_size, 0));
@@ -659,6 +751,18 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
659751

660752
flutter::Settings settings = flutter::SettingsFromCommandLine(command_line);
661753

754+
if (SAFE_ACCESS(args, aot_data, nullptr)) {
755+
if (SAFE_ACCESS(args, vm_snapshot_data, nullptr) ||
756+
SAFE_ACCESS(args, vm_snapshot_instructions, nullptr) ||
757+
SAFE_ACCESS(args, isolate_snapshot_data, nullptr) ||
758+
SAFE_ACCESS(args, isolate_snapshot_instructions, nullptr)) {
759+
return LOG_EMBEDDER_ERROR(
760+
kInvalidArguments,
761+
"Multiple AOT sources specified. Embedders should provide either "
762+
"*_snapshot_* buffers or aot_data, not both.");
763+
}
764+
}
765+
662766
PopulateSnapshotMappingCallbacks(args, settings);
663767

664768
settings.icu_data_path = icu_data_path;

shell/platform/embedder/embedder.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,57 @@ typedef enum {
959959
typedef void (*FlutterNativeThreadCallback)(FlutterNativeThreadType type,
960960
void* user_data);
961961

962+
/// AOT data source type.
963+
typedef enum {
964+
kFlutterEngineAOTDataSourceTypeElfPath
965+
} FlutterEngineAOTDataSourceType;
966+
967+
/// This struct specifies one of the various locations the engine can look for
968+
/// AOT data sources.
969+
typedef struct {
970+
FlutterEngineAOTDataSourceType type;
971+
union {
972+
/// Absolute path to an ELF library file.
973+
const char* elf_path;
974+
};
975+
} FlutterEngineAOTDataSource;
976+
977+
/// An opaque object that describes the AOT data that can be used to launch a
978+
/// FlutterEngine instance in AOT mode.
979+
typedef struct _FlutterEngineAOTData* FlutterEngineAOTData;
980+
981+
//------------------------------------------------------------------------------
982+
/// @brief Creates the necessary data structures to launch a Flutter Dart
983+
/// application in AOT mode. The data may only be collected after
984+
/// all FlutterEngine instances launched using this data have been
985+
/// terminated.
986+
///
987+
/// @param[in] source The source of the AOT data.
988+
/// @param[out] data_out The AOT data on success. Unchanged on failure.
989+
///
990+
/// @return Returns if the AOT data could be successfully resolved.
991+
///
992+
FLUTTER_EXPORT
993+
FlutterEngineResult FlutterEngineCreateAOTData(
994+
const FlutterEngineAOTDataSource* source,
995+
FlutterEngineAOTData* data_out);
996+
997+
//------------------------------------------------------------------------------
998+
/// @brief Collects the AOT data.
999+
///
1000+
/// @warning The embedder must ensure that this call is made only after all
1001+
/// FlutterEngine instances launched using this data have been
1002+
/// terminated, and that all of those instances were launched with
1003+
/// the FlutterProjectArgs::shutdown_dart_vm_when_done flag set to
1004+
/// true.
1005+
///
1006+
/// @param[in] data The data to collect.
1007+
///
1008+
/// @return Returns if the AOT data was successfully collected.
1009+
///
1010+
FLUTTER_EXPORT
1011+
FlutterEngineResult FlutterEngineCollectAOTData(FlutterEngineAOTData data);
1012+
9621013
typedef struct {
9631014
/// The size of this struct. Must be sizeof(FlutterProjectArgs).
9641015
size_t struct_size;
@@ -1146,6 +1197,14 @@ typedef struct {
11461197
/// See also:
11471198
/// https://github.com/dart-lang/sdk/blob/ca64509108b3e7219c50d6c52877c85ab6a35ff2/runtime/vm/flag_list.h#L150
11481199
int64_t dart_old_gen_heap_size;
1200+
1201+
/// The AOT data to be used in AOT operation.
1202+
///
1203+
/// Embedders should instantiate and destroy this object via the
1204+
/// FlutterEngineCreateAOTData and FlutterEngineCollectAOTData methods.
1205+
///
1206+
/// Embedders can provide either snapshot buffers or aot_data, but not both.
1207+
FlutterEngineAOTData aot_data;
11491208
} FlutterProjectArgs;
11501209

11511210
//------------------------------------------------------------------------------

shell/platform/embedder/tests/embedder_config_builder.cc

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "flutter/shell/platform/embedder/tests/embedder_config_builder.h"
66

7+
#include "flutter/runtime/dart_vm.h"
78
#include "flutter/shell/platform/embedder/embedder.h"
89
#include "third_party/skia/include/core/SkBitmap.h"
910

@@ -75,12 +76,20 @@ EmbedderConfigBuilder::EmbedderConfigBuilder(
7576
// to do this manually.
7677
AddCommandLineArgument("embedder_unittest");
7778

78-
if (preference == InitializationPreference::kInitialize) {
79+
if (preference != InitializationPreference::kNoInitialize) {
7980
SetAssetsPath();
80-
SetSnapshots();
8181
SetIsolateCreateCallbackHook();
8282
SetSemanticsCallbackHooks();
8383
AddCommandLineArgument("--disable-observatory");
84+
85+
if (preference == InitializationPreference::kSnapshotsInitialize ||
86+
preference == InitializationPreference::kMultiAOTInitialize) {
87+
SetSnapshots();
88+
}
89+
if (preference == InitializationPreference::kAOTDataInitialize ||
90+
preference == InitializationPreference::kMultiAOTInitialize) {
91+
SetAOTDataElf();
92+
}
8493
}
8594
}
8695

@@ -132,6 +141,10 @@ void EmbedderConfigBuilder::SetSnapshots() {
132141
}
133142
}
134143

144+
void EmbedderConfigBuilder::SetAOTDataElf() {
145+
project_args_.aot_data = context_.GetAOTData();
146+
}
147+
135148
void EmbedderConfigBuilder::SetIsolateCreateCallbackHook() {
136149
project_args_.root_isolate_create_callback =
137150
EmbedderTestContext::GetIsolateCreateCallbackHook();

shell/platform/embedder/tests/embedder_config_builder.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@ using UniqueEngine = fml::UniqueObject<FlutterEngine, UniqueEngineTraits>;
3131
class EmbedderConfigBuilder {
3232
public:
3333
enum class InitializationPreference {
34-
kInitialize,
34+
kSnapshotsInitialize,
35+
kAOTDataInitialize,
36+
kMultiAOTInitialize,
3537
kNoInitialize,
3638
};
3739

3840
EmbedderConfigBuilder(EmbedderTestContext& context,
3941
InitializationPreference preference =
40-
InitializationPreference::kInitialize);
42+
InitializationPreference::kSnapshotsInitialize);
4143

4244
~EmbedderConfigBuilder();
4345

@@ -51,6 +53,8 @@ class EmbedderConfigBuilder {
5153

5254
void SetSnapshots();
5355

56+
void SetAOTDataElf();
57+
5458
void SetIsolateCreateCallbackHook();
5559

5660
void SetSemanticsCallbackHooks();

shell/platform/embedder/tests/embedder_test_context.cc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "flutter/fml/paths.h"
99
#include "flutter/runtime/dart_vm.h"
1010
#include "flutter/shell/platform/embedder/tests/embedder_assertions.h"
11+
#include "flutter/testing/testing.h"
1112
#include "third_party/dart/runtime/bin/elf_loader.h"
1213
#include "third_party/skia/include/core/SkSurface.h"
1314

@@ -19,6 +20,7 @@ EmbedderTestContext::EmbedderTestContext(std::string assets_path)
1920
aot_symbols_(LoadELFSymbolFromFixturesIfNeccessary()),
2021
native_resolver_(std::make_shared<TestDartNativeResolver>()) {
2122
SetupAOTMappingsIfNecessary();
23+
SetupAOTDataIfNecessary();
2224
isolate_create_callbacks_.push_back(
2325
[weak_resolver =
2426
std::weak_ptr<TestDartNativeResolver>{native_resolver_}]() {
@@ -44,6 +46,24 @@ void EmbedderTestContext::SetupAOTMappingsIfNecessary() {
4446
aot_symbols_.vm_isolate_instrs, 0u);
4547
}
4648

49+
void EmbedderTestContext::SetupAOTDataIfNecessary() {
50+
if (!DartVM::IsRunningPrecompiledCode()) {
51+
return;
52+
}
53+
FlutterEngineAOTDataSource data_in = {};
54+
FlutterEngineAOTData data_out = nullptr;
55+
56+
const auto elf_path =
57+
fml::paths::JoinPaths({GetFixturesPath(), kAOTAppELFFileName});
58+
59+
data_in.type = kFlutterEngineAOTDataSourceTypeElfPath;
60+
data_in.elf_path = elf_path.c_str();
61+
62+
ASSERT_EQ(FlutterEngineCreateAOTData(&data_in, &data_out), kSuccess);
63+
64+
aot_data_.reset(data_out);
65+
}
66+
4767
const std::string& EmbedderTestContext::GetAssetsPath() const {
4868
return assets_path_;
4969
}
@@ -65,6 +85,10 @@ const fml::Mapping* EmbedderTestContext::GetIsolateSnapshotInstructions()
6585
return isolate_snapshot_instructions_.get();
6686
}
6787

88+
FlutterEngineAOTData EmbedderTestContext::GetAOTData() const {
89+
return aot_data_.get();
90+
}
91+
6892
void EmbedderTestContext::SetRootSurfaceTransformation(SkMatrix matrix) {
6993
root_surface_transformation_ = matrix;
7094
}

shell/platform/embedder/tests/embedder_test_context.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ using SemanticsNodeCallback = std::function<void(const FlutterSemanticsNode*)>;
2828
using SemanticsActionCallback =
2929
std::function<void(const FlutterSemanticsCustomAction*)>;
3030

31+
struct AOTDataDeleter {
32+
void operator()(FlutterEngineAOTData aot_data) {
33+
if (aot_data) {
34+
FlutterEngineCollectAOTData(aot_data);
35+
}
36+
}
37+
};
38+
39+
using UniqueAOTData = std::unique_ptr<_FlutterEngineAOTData, AOTDataDeleter>;
40+
3141
class EmbedderTestContext {
3242
public:
3343
EmbedderTestContext(std::string assets_path = "");
@@ -44,6 +54,8 @@ class EmbedderTestContext {
4454

4555
const fml::Mapping* GetIsolateSnapshotInstructions() const;
4656

57+
FlutterEngineAOTData GetAOTData() const;
58+
4759
void SetRootSurfaceTransformation(SkMatrix matrix);
4860

4961
void AddIsolateCreateCallback(fml::closure closure);
@@ -79,6 +91,7 @@ class EmbedderTestContext {
7991
std::unique_ptr<fml::Mapping> vm_snapshot_instructions_;
8092
std::unique_ptr<fml::Mapping> isolate_snapshot_data_;
8193
std::unique_ptr<fml::Mapping> isolate_snapshot_instructions_;
94+
UniqueAOTData aot_data_;
8295
std::vector<fml::closure> isolate_create_callbacks_;
8396
std::shared_ptr<TestDartNativeResolver> native_resolver_;
8497
SemanticsNodeCallback update_semantics_node_callback_;
@@ -101,6 +114,8 @@ class EmbedderTestContext {
101114

102115
void SetupAOTMappingsIfNecessary();
103116

117+
void SetupAOTDataIfNecessary();
118+
104119
void SetupCompositor();
105120

106121
void FireIsolateCreateCallbacks();

0 commit comments

Comments
 (0)