Skip to content

Commit

Permalink
Add new FlutterEngineAOTData argument to FlutterProjectArgs (flutter#…
Browse files Browse the repository at this point in the history
…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/flutter#50778
  • Loading branch information
MarcusTomlinson authored May 10, 2020
1 parent 9913400 commit d96f962
Show file tree
Hide file tree
Showing 10 changed files with 335 additions and 6 deletions.
1 change: 1 addition & 0 deletions shell/platform/embedder/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ template("embedder_source_set") {
"//flutter/shell/common",
"//flutter/third_party/tonic",
"//third_party/dart/runtime/bin:dart_io_api",
"//third_party/dart/runtime/bin:elf_loader",
"//third_party/skia",
]

Expand Down
104 changes: 104 additions & 0 deletions shell/platform/embedder/embedder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "flutter/fml/closure.h"
#include "flutter/fml/make_copyable.h"
#include "flutter/fml/native_library.h"
#include "third_party/dart/runtime/bin/elf_loader.h"
#include "third_party/dart/runtime/include/dart_native_api.h"

#if OS_WIN
Expand Down Expand Up @@ -532,6 +533,83 @@ struct _FlutterPlatformMessageResponseHandle {
fml::RefPtr<flutter::PlatformMessage> message;
};

struct LoadedElfDeleter {
void operator()(Dart_LoadedElf* elf) {
if (elf) {
::Dart_UnloadELF(elf);
}
}
};

using UniqueLoadedElf = std::unique_ptr<Dart_LoadedElf, LoadedElfDeleter>;

struct _FlutterEngineAOTData {
UniqueLoadedElf loaded_elf = nullptr;
const uint8_t* vm_snapshot_data = nullptr;
const uint8_t* vm_snapshot_instrs = nullptr;
const uint8_t* vm_isolate_data = nullptr;
const uint8_t* vm_isolate_instrs = nullptr;
};

FlutterEngineResult FlutterEngineCreateAOTData(
const FlutterEngineAOTDataSource* source,
FlutterEngineAOTData* data_out) {
if (!flutter::DartVM::IsRunningPrecompiledCode()) {
return LOG_EMBEDDER_ERROR(kInvalidArguments,
"AOT data can only be created in AOT mode.");
} else if (!source) {
return LOG_EMBEDDER_ERROR(kInvalidArguments, "Null source specified.");
} else if (!data_out) {
return LOG_EMBEDDER_ERROR(kInvalidArguments, "Null data_out specified.");
}

switch (source->type) {
case kFlutterEngineAOTDataSourceTypeElfPath: {
if (!source->elf_path || !fml::IsFile(source->elf_path)) {
return LOG_EMBEDDER_ERROR(kInvalidArguments,
"Invalid ELF path specified.");
}

auto aot_data = std::make_unique<_FlutterEngineAOTData>();
const char* error = nullptr;

Dart_LoadedElf* loaded_elf = Dart_LoadELF(
source->elf_path, // file path
0, // file offset
&error, // error (out)
&aot_data->vm_snapshot_data, // vm snapshot data (out)
&aot_data->vm_snapshot_instrs, // vm snapshot instr (out)
&aot_data->vm_isolate_data, // vm isolate data (out)
&aot_data->vm_isolate_instrs // vm isolate instr (out)
);

if (loaded_elf == nullptr) {
return LOG_EMBEDDER_ERROR(kInvalidArguments, error);
}

aot_data->loaded_elf.reset(loaded_elf);

*data_out = aot_data.release();
return kSuccess;
}
}

return LOG_EMBEDDER_ERROR(
kInvalidArguments,
"Invalid FlutterEngineAOTDataSourceType type specified.");
}

FlutterEngineResult FlutterEngineCollectAOTData(FlutterEngineAOTData data) {
if (data) {
data->loaded_elf = nullptr;
data->vm_snapshot_data = nullptr;
data->vm_snapshot_instrs = nullptr;
data->vm_isolate_data = nullptr;
data->vm_isolate_instrs = nullptr;
}
return kSuccess;
}

void PopulateSnapshotMappingCallbacks(const FlutterProjectArgs* args,
flutter::Settings& settings) {
// There are no ownership concerns here as all mappings are owned by the
Expand All @@ -543,6 +621,20 @@ void PopulateSnapshotMappingCallbacks(const FlutterProjectArgs* args,
};

if (flutter::DartVM::IsRunningPrecompiledCode()) {
if (SAFE_ACCESS(args, aot_data, nullptr) != nullptr) {
settings.vm_snapshot_data =
make_mapping_callback(args->aot_data->vm_snapshot_data, 0);

settings.vm_snapshot_instr =
make_mapping_callback(args->aot_data->vm_snapshot_instrs, 0);

settings.isolate_snapshot_data =
make_mapping_callback(args->aot_data->vm_isolate_data, 0);

settings.isolate_snapshot_instr =
make_mapping_callback(args->aot_data->vm_isolate_instrs, 0);
}

if (SAFE_ACCESS(args, vm_snapshot_data, nullptr) != nullptr) {
settings.vm_snapshot_data = make_mapping_callback(
args->vm_snapshot_data, SAFE_ACCESS(args, vm_snapshot_data_size, 0));
Expand Down Expand Up @@ -659,6 +751,18 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,

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

if (SAFE_ACCESS(args, aot_data, nullptr)) {
if (SAFE_ACCESS(args, vm_snapshot_data, nullptr) ||
SAFE_ACCESS(args, vm_snapshot_instructions, nullptr) ||
SAFE_ACCESS(args, isolate_snapshot_data, nullptr) ||
SAFE_ACCESS(args, isolate_snapshot_instructions, nullptr)) {
return LOG_EMBEDDER_ERROR(
kInvalidArguments,
"Multiple AOT sources specified. Embedders should provide either "
"*_snapshot_* buffers or aot_data, not both.");
}
}

PopulateSnapshotMappingCallbacks(args, settings);

settings.icu_data_path = icu_data_path;
Expand Down
59 changes: 59 additions & 0 deletions shell/platform/embedder/embedder.h
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,57 @@ typedef enum {
typedef void (*FlutterNativeThreadCallback)(FlutterNativeThreadType type,
void* user_data);

/// AOT data source type.
typedef enum {
kFlutterEngineAOTDataSourceTypeElfPath
} FlutterEngineAOTDataSourceType;

/// This struct specifies one of the various locations the engine can look for
/// AOT data sources.
typedef struct {
FlutterEngineAOTDataSourceType type;
union {
/// Absolute path to an ELF library file.
const char* elf_path;
};
} FlutterEngineAOTDataSource;

/// An opaque object that describes the AOT data that can be used to launch a
/// FlutterEngine instance in AOT mode.
typedef struct _FlutterEngineAOTData* FlutterEngineAOTData;

//------------------------------------------------------------------------------
/// @brief Creates the necessary data structures to launch a Flutter Dart
/// application in AOT mode. The data may only be collected after
/// all FlutterEngine instances launched using this data have been
/// terminated.
///
/// @param[in] source The source of the AOT data.
/// @param[out] data_out The AOT data on success. Unchanged on failure.
///
/// @return Returns if the AOT data could be successfully resolved.
///
FLUTTER_EXPORT
FlutterEngineResult FlutterEngineCreateAOTData(
const FlutterEngineAOTDataSource* source,
FlutterEngineAOTData* data_out);

//------------------------------------------------------------------------------
/// @brief Collects the AOT data.
///
/// @warning The embedder must ensure that this call is made only after all
/// FlutterEngine instances launched using this data have been
/// terminated, and that all of those instances were launched with
/// the FlutterProjectArgs::shutdown_dart_vm_when_done flag set to
/// true.
///
/// @param[in] data The data to collect.
///
/// @return Returns if the AOT data was successfully collected.
///
FLUTTER_EXPORT
FlutterEngineResult FlutterEngineCollectAOTData(FlutterEngineAOTData data);

typedef struct {
/// The size of this struct. Must be sizeof(FlutterProjectArgs).
size_t struct_size;
Expand Down Expand Up @@ -1146,6 +1197,14 @@ typedef struct {
/// See also:
/// https://github.com/dart-lang/sdk/blob/ca64509108b3e7219c50d6c52877c85ab6a35ff2/runtime/vm/flag_list.h#L150
int64_t dart_old_gen_heap_size;

/// The AOT data to be used in AOT operation.
///
/// Embedders should instantiate and destroy this object via the
/// FlutterEngineCreateAOTData and FlutterEngineCollectAOTData methods.
///
/// Embedders can provide either snapshot buffers or aot_data, but not both.
FlutterEngineAOTData aot_data;
} FlutterProjectArgs;

//------------------------------------------------------------------------------
Expand Down
17 changes: 15 additions & 2 deletions shell/platform/embedder/tests/embedder_config_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

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

#include "flutter/runtime/dart_vm.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "third_party/skia/include/core/SkBitmap.h"

Expand Down Expand Up @@ -75,12 +76,20 @@ EmbedderConfigBuilder::EmbedderConfigBuilder(
// to do this manually.
AddCommandLineArgument("embedder_unittest");

if (preference == InitializationPreference::kInitialize) {
if (preference != InitializationPreference::kNoInitialize) {
SetAssetsPath();
SetSnapshots();
SetIsolateCreateCallbackHook();
SetSemanticsCallbackHooks();
AddCommandLineArgument("--disable-observatory");

if (preference == InitializationPreference::kSnapshotsInitialize ||
preference == InitializationPreference::kMultiAOTInitialize) {
SetSnapshots();
}
if (preference == InitializationPreference::kAOTDataInitialize ||
preference == InitializationPreference::kMultiAOTInitialize) {
SetAOTDataElf();
}
}
}

Expand Down Expand Up @@ -132,6 +141,10 @@ void EmbedderConfigBuilder::SetSnapshots() {
}
}

void EmbedderConfigBuilder::SetAOTDataElf() {
project_args_.aot_data = context_.GetAOTData();
}

void EmbedderConfigBuilder::SetIsolateCreateCallbackHook() {
project_args_.root_isolate_create_callback =
EmbedderTestContext::GetIsolateCreateCallbackHook();
Expand Down
8 changes: 6 additions & 2 deletions shell/platform/embedder/tests/embedder_config_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ using UniqueEngine = fml::UniqueObject<FlutterEngine, UniqueEngineTraits>;
class EmbedderConfigBuilder {
public:
enum class InitializationPreference {
kInitialize,
kSnapshotsInitialize,
kAOTDataInitialize,
kMultiAOTInitialize,
kNoInitialize,
};

EmbedderConfigBuilder(EmbedderTestContext& context,
InitializationPreference preference =
InitializationPreference::kInitialize);
InitializationPreference::kSnapshotsInitialize);

~EmbedderConfigBuilder();

Expand All @@ -51,6 +53,8 @@ class EmbedderConfigBuilder {

void SetSnapshots();

void SetAOTDataElf();

void SetIsolateCreateCallbackHook();

void SetSemanticsCallbackHooks();
Expand Down
24 changes: 24 additions & 0 deletions shell/platform/embedder/tests/embedder_test_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "flutter/fml/paths.h"
#include "flutter/runtime/dart_vm.h"
#include "flutter/shell/platform/embedder/tests/embedder_assertions.h"
#include "flutter/testing/testing.h"
#include "third_party/dart/runtime/bin/elf_loader.h"
#include "third_party/skia/include/core/SkSurface.h"

Expand All @@ -19,6 +20,7 @@ EmbedderTestContext::EmbedderTestContext(std::string assets_path)
aot_symbols_(LoadELFSymbolFromFixturesIfNeccessary()),
native_resolver_(std::make_shared<TestDartNativeResolver>()) {
SetupAOTMappingsIfNecessary();
SetupAOTDataIfNecessary();
isolate_create_callbacks_.push_back(
[weak_resolver =
std::weak_ptr<TestDartNativeResolver>{native_resolver_}]() {
Expand All @@ -44,6 +46,24 @@ void EmbedderTestContext::SetupAOTMappingsIfNecessary() {
aot_symbols_.vm_isolate_instrs, 0u);
}

void EmbedderTestContext::SetupAOTDataIfNecessary() {
if (!DartVM::IsRunningPrecompiledCode()) {
return;
}
FlutterEngineAOTDataSource data_in = {};
FlutterEngineAOTData data_out = nullptr;

const auto elf_path =
fml::paths::JoinPaths({GetFixturesPath(), kAOTAppELFFileName});

data_in.type = kFlutterEngineAOTDataSourceTypeElfPath;
data_in.elf_path = elf_path.c_str();

ASSERT_EQ(FlutterEngineCreateAOTData(&data_in, &data_out), kSuccess);

aot_data_.reset(data_out);
}

const std::string& EmbedderTestContext::GetAssetsPath() const {
return assets_path_;
}
Expand All @@ -65,6 +85,10 @@ const fml::Mapping* EmbedderTestContext::GetIsolateSnapshotInstructions()
return isolate_snapshot_instructions_.get();
}

FlutterEngineAOTData EmbedderTestContext::GetAOTData() const {
return aot_data_.get();
}

void EmbedderTestContext::SetRootSurfaceTransformation(SkMatrix matrix) {
root_surface_transformation_ = matrix;
}
Expand Down
15 changes: 15 additions & 0 deletions shell/platform/embedder/tests/embedder_test_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ using SemanticsNodeCallback = std::function<void(const FlutterSemanticsNode*)>;
using SemanticsActionCallback =
std::function<void(const FlutterSemanticsCustomAction*)>;

struct AOTDataDeleter {
void operator()(FlutterEngineAOTData aot_data) {
if (aot_data) {
FlutterEngineCollectAOTData(aot_data);
}
}
};

using UniqueAOTData = std::unique_ptr<_FlutterEngineAOTData, AOTDataDeleter>;

class EmbedderTestContext {
public:
EmbedderTestContext(std::string assets_path = "");
Expand All @@ -44,6 +54,8 @@ class EmbedderTestContext {

const fml::Mapping* GetIsolateSnapshotInstructions() const;

FlutterEngineAOTData GetAOTData() const;

void SetRootSurfaceTransformation(SkMatrix matrix);

void AddIsolateCreateCallback(fml::closure closure);
Expand Down Expand Up @@ -79,6 +91,7 @@ class EmbedderTestContext {
std::unique_ptr<fml::Mapping> vm_snapshot_instructions_;
std::unique_ptr<fml::Mapping> isolate_snapshot_data_;
std::unique_ptr<fml::Mapping> isolate_snapshot_instructions_;
UniqueAOTData aot_data_;
std::vector<fml::closure> isolate_create_callbacks_;
std::shared_ptr<TestDartNativeResolver> native_resolver_;
SemanticsNodeCallback update_semantics_node_callback_;
Expand All @@ -101,6 +114,8 @@ class EmbedderTestContext {

void SetupAOTMappingsIfNecessary();

void SetupAOTDataIfNecessary();

void SetupCompositor();

void FireIsolateCreateCallbacks();
Expand Down
Loading

0 comments on commit d96f962

Please sign in to comment.