mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Add new FlutterEngineAOTData argument to FlutterProjectArgs (flutter/engine#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: https://github.com/flutter/flutter/issues/50778
This commit is contained in:
parent
4f857fbd46
commit
7d5268265e
@ -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",
|
||||
]
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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));
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
@ -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;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -51,6 +53,8 @@ class EmbedderConfigBuilder {
|
||||
|
||||
void SetSnapshots();
|
||||
|
||||
void SetAOTDataElf();
|
||||
|
||||
void SetIsolateCreateCallbackHook();
|
||||
|
||||
void SetSemanticsCallbackHooks();
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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_}]() {
|
||||
@ -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_;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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 = "");
|
||||
@ -44,6 +54,8 @@ class EmbedderTestContext {
|
||||
|
||||
const fml::Mapping* GetIsolateSnapshotInstructions() const;
|
||||
|
||||
FlutterEngineAOTData GetAOTData() const;
|
||||
|
||||
void SetRootSurfaceTransformation(SkMatrix matrix);
|
||||
|
||||
void AddIsolateCreateCallback(fml::closure closure);
|
||||
@ -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_;
|
||||
@ -101,6 +114,8 @@ class EmbedderTestContext {
|
||||
|
||||
void SetupAOTMappingsIfNecessary();
|
||||
|
||||
void SetupAOTDataIfNecessary();
|
||||
|
||||
void SetupCompositor();
|
||||
|
||||
void FireIsolateCreateCallbacks();
|
||||
|
||||
@ -4207,5 +4207,114 @@ TEST_F(EmbedderTest, CompositorRenderTargetsAreInStableOrder) {
|
||||
latch.Wait();
|
||||
}
|
||||
|
||||
TEST_F(EmbedderTest, InvalidAOTDataSourcesMustReturnError) {
|
||||
if (!DartVM::IsRunningPrecompiledCode()) {
|
||||
GTEST_SKIP();
|
||||
return;
|
||||
}
|
||||
FlutterEngineAOTDataSource data_in = {};
|
||||
FlutterEngineAOTData data_out = nullptr;
|
||||
|
||||
// Null source specified.
|
||||
ASSERT_EQ(FlutterEngineCreateAOTData(nullptr, &data_out), kInvalidArguments);
|
||||
ASSERT_EQ(data_out, nullptr);
|
||||
|
||||
// Null data_out specified.
|
||||
ASSERT_EQ(FlutterEngineCreateAOTData(&data_in, nullptr), kInvalidArguments);
|
||||
|
||||
// Invalid FlutterEngineAOTDataSourceType type specified.
|
||||
data_in.type = FlutterEngineAOTDataSourceType(-1);
|
||||
ASSERT_EQ(FlutterEngineCreateAOTData(&data_in, &data_out), kInvalidArguments);
|
||||
ASSERT_EQ(data_out, nullptr);
|
||||
|
||||
// Invalid ELF path specified.
|
||||
data_in.type = kFlutterEngineAOTDataSourceTypeElfPath;
|
||||
data_in.elf_path = nullptr;
|
||||
ASSERT_EQ(FlutterEngineCreateAOTData(&data_in, &data_out), kInvalidArguments);
|
||||
ASSERT_EQ(data_in.type, kFlutterEngineAOTDataSourceTypeElfPath);
|
||||
ASSERT_EQ(data_in.elf_path, nullptr);
|
||||
ASSERT_EQ(data_out, nullptr);
|
||||
|
||||
// Invalid ELF path specified.
|
||||
data_in.elf_path = "";
|
||||
ASSERT_EQ(FlutterEngineCreateAOTData(&data_in, &data_out), kInvalidArguments);
|
||||
ASSERT_EQ(data_in.type, kFlutterEngineAOTDataSourceTypeElfPath);
|
||||
ASSERT_EQ(data_in.elf_path, "");
|
||||
ASSERT_EQ(data_out, nullptr);
|
||||
|
||||
// Could not find VM snapshot data.
|
||||
data_in.elf_path = "/bin/true";
|
||||
ASSERT_EQ(FlutterEngineCreateAOTData(&data_in, &data_out), kInvalidArguments);
|
||||
ASSERT_EQ(data_in.type, kFlutterEngineAOTDataSourceTypeElfPath);
|
||||
ASSERT_EQ(data_in.elf_path, "/bin/true");
|
||||
ASSERT_EQ(data_out, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(EmbedderTest, MustNotRunWithMultipleAOTSources) {
|
||||
if (!DartVM::IsRunningPrecompiledCode()) {
|
||||
GTEST_SKIP();
|
||||
return;
|
||||
}
|
||||
auto& context = GetEmbedderContext();
|
||||
|
||||
EmbedderConfigBuilder builder(
|
||||
context,
|
||||
EmbedderConfigBuilder::InitializationPreference::kMultiAOTInitialize);
|
||||
|
||||
builder.SetSoftwareRendererConfig();
|
||||
|
||||
auto engine = builder.LaunchEngine();
|
||||
ASSERT_FALSE(engine.is_valid());
|
||||
}
|
||||
|
||||
TEST_F(EmbedderTest, CanCreateAndCollectAValidElfSource) {
|
||||
if (!DartVM::IsRunningPrecompiledCode()) {
|
||||
GTEST_SKIP();
|
||||
return;
|
||||
}
|
||||
FlutterEngineAOTDataSource data_in = {};
|
||||
FlutterEngineAOTData data_out = nullptr;
|
||||
|
||||
// Collecting a null object should be allowed
|
||||
ASSERT_EQ(FlutterEngineCollectAOTData(data_out), kSuccess);
|
||||
|
||||
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);
|
||||
ASSERT_EQ(data_in.type, kFlutterEngineAOTDataSourceTypeElfPath);
|
||||
ASSERT_EQ(data_in.elf_path, elf_path.c_str());
|
||||
ASSERT_NE(data_out, nullptr);
|
||||
|
||||
ASSERT_EQ(FlutterEngineCollectAOTData(data_out), kSuccess);
|
||||
}
|
||||
|
||||
TEST_F(EmbedderTest, CanLaunchAndShutdownWithAValidElfSource) {
|
||||
if (!DartVM::IsRunningPrecompiledCode()) {
|
||||
GTEST_SKIP();
|
||||
return;
|
||||
}
|
||||
auto& context = GetEmbedderContext();
|
||||
|
||||
fml::AutoResetWaitableEvent latch;
|
||||
context.AddIsolateCreateCallback([&latch]() { latch.Signal(); });
|
||||
|
||||
EmbedderConfigBuilder builder(
|
||||
context,
|
||||
EmbedderConfigBuilder::InitializationPreference::kAOTDataInitialize);
|
||||
|
||||
builder.SetSoftwareRendererConfig();
|
||||
|
||||
auto engine = builder.LaunchEngine();
|
||||
ASSERT_TRUE(engine.is_valid());
|
||||
|
||||
// Wait for the root isolate to launch.
|
||||
latch.Wait();
|
||||
engine.reset();
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
|
||||
@ -12,8 +12,6 @@
|
||||
namespace flutter {
|
||||
namespace testing {
|
||||
|
||||
static constexpr const char* kAOTAppELFFileName = "app_elf_snapshot.so";
|
||||
|
||||
ELFAOTSymbols LoadELFSymbolFromFixturesIfNeccessary() {
|
||||
if (!DartVM::IsRunningPrecompiledCode()) {
|
||||
return {};
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
namespace flutter {
|
||||
namespace testing {
|
||||
|
||||
inline constexpr const char* kAOTAppELFFileName = "app_elf_snapshot.so";
|
||||
|
||||
struct LoadedELFDeleter {
|
||||
void operator()(Dart_LoadedElf* elf) { ::Dart_UnloadELF(elf); }
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user