Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
284 changes: 271 additions & 13 deletions .github/workflows/build-and-upload-engine-artifacts.yml

Large diffs are not rendered by default.

41 changes: 41 additions & 0 deletions engine/src/flutter/shell/platform/embedder/embedder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "flutter/fml/build_config.h"
#include "flutter/fml/closure.h"
#include "flutter/fml/make_copyable.h"
#include "flutter/fml/native_library.h"
#include "flutter/fml/thread.h"
#include "third_party/dart/runtime/bin/elf_loader.h"
#include "third_party/dart/runtime/include/dart_native_api.h"
Expand Down Expand Up @@ -91,6 +92,7 @@ using UniqueLoadedElf = std::unique_ptr<Dart_LoadedElf, LoadedElfDeleter>;

struct _FlutterEngineAOTData {
UniqueLoadedElf loaded_elf = nullptr;
fml::RefPtr<fml::NativeLibrary> native_library = nullptr;
const uint8_t* vm_snapshot_data = nullptr;
const uint8_t* vm_snapshot_instrs = nullptr;
const uint8_t* vm_isolate_data = nullptr;
Expand Down Expand Up @@ -146,6 +148,45 @@ FlutterEngineResult FlutterEngineCreateAOTData(
*data_out = aot_data.release();
return kSuccess;
}
case kFlutterEngineAOTDataSourceTypeDllPath: {
// TODO(team-windows): Support PE/COFF AOT snapshots for Windows Arm64.
// See: https://github.com/flutter/flutter/issues/190897
#if FML_OS_WIN && FML_ARCH_CPU_X86_64
if (!source->dll_path || !fml::IsFile(source->dll_path)) {
return LOG_EMBEDDER_ERROR(kInvalidArguments,
"Invalid DLL path specified.");
}

auto native_library = fml::NativeLibrary::Create(source->dll_path);
if (!native_library) {
return LOG_EMBEDDER_ERROR(kInvalidArguments,
"Could not load DLL path specified.");
}

auto aot_data = std::make_unique<_FlutterEngineAOTData>();
aot_data->native_library = std::move(native_library);
aot_data->vm_snapshot_data =
aot_data->native_library->ResolveSymbol("_kDartSnapshotData");
aot_data->vm_snapshot_instrs =
aot_data->native_library->ResolveSymbol("_kDartSnapshotText");
aot_data->vm_isolate_data = aot_data->vm_snapshot_data;
aot_data->vm_isolate_instrs = aot_data->vm_snapshot_instrs;

if (aot_data->vm_snapshot_data == nullptr ||
aot_data->vm_snapshot_instrs == nullptr) {
return LOG_EMBEDDER_ERROR(
kInvalidArguments,
"Could not resolve required AOT snapshot symbols from DLL.");
}

*data_out = aot_data.release();
return kSuccess;
#else // FML_OS_WIN && FML_ARCH_CPU_X86_64
return LOG_EMBEDDER_ERROR(
kInvalidArguments,
"DLL AOT data sources are only supported on Windows x64.");
#endif // FML_OS_WIN && FML_ARCH_CPU_X86_64
}
}

return LOG_EMBEDDER_ERROR(
Expand Down
5 changes: 4 additions & 1 deletion engine/src/flutter/shell/platform/embedder/embedder.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,8 @@ typedef void (*FlutterNativeThreadCallback)(FlutterNativeThreadType type,

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

/// This struct specifies one of the various locations the engine can look for
Expand All @@ -342,6 +343,8 @@ typedef struct {
union {
/// Absolute path to an ELF library file.
const char* elf_path;
/// Absolute path to a native dynamic library file.
const char* dll_path;
};
} FlutterEngineAOTDataSource;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <filesystem>

#include "flutter/fml/build_config.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/string_conversion.h"
#include "flutter/shell/platform/common/engine_switches.h" // nogncheck
Expand Down Expand Up @@ -70,8 +71,13 @@ UniqueAotDataPtr FlutterProjectBundle::LoadAotData(
}
std::string path_string = fml::PathToUtf8(aot_library_path_);
FlutterEngineAOTDataSource source = {};
#if FML_ARCH_CPU_X86_64
source.type = kFlutterEngineAOTDataSourceTypeDllPath;
source.dll_path = path_string.c_str();
#else
source.type = kFlutterEngineAOTDataSourceTypeElfPath;
source.elf_path = path_string.c_str();
#endif
FlutterEngineAOTData data = nullptr;
auto result = engine_procs.CreateAOTData(&source, &data);
if (result != kSuccess) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <filesystem>
#include <thread>
#include "flutter/shell/platform/windows/flutter_windows_engine.h"

#include "flutter/fml/build_config.h"
#include "flutter/fml/string_conversion.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
#include "flutter/shell/platform/windows/testing/engine_modifier.h"
#include "flutter/shell/platform/windows/testing/flutter_windows_engine_builder.h"
#include "flutter/shell/platform/windows/testing/mock_windows_proc_table.h"
#include "flutter/shell/platform/windows/testing/windows_test.h"
#include "flutter/testing/testing.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"

Expand Down Expand Up @@ -122,6 +126,76 @@ TEST_F(FlutterWindowsEngineTest, TaskRunnerDoesNotDeadlock) {
UnregisterClassW(class_name, nullptr);
}

// Verify that Run creates the AOT data using the source type expected for
// the current architecture.
TEST_F(FlutterWindowsEngineTest, RunLoadsAotDataWithExpectedSourceType) {
// Loading AOT data requires that the AOT library exist on disk. Use a
// fixture source file as a stand-in; its contents are irrelevant since
// CreateAOTData is mocked below.
std::filesystem::path aot_library_path =
std::filesystem::path{GetSourcePath()} /
"flutter/shell/platform/windows/fixtures/main.dart";
ASSERT_TRUE(std::filesystem::exists(aot_library_path));

FlutterWindowsEngineBuilder builder{GetContext()};
builder.SetAotLibraryPath(aot_library_path.wstring());
std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
EngineModifier modifier(engine.get());

modifier.embedder_api().RunsAOTCompiledDartCode = []() { return true; };

bool create_aot_data_called = false;
FlutterEngineAOTDataSourceType source_type =
kFlutterEngineAOTDataSourceTypeElfPath;
std::string source_path;
modifier.embedder_api().CreateAOTData = MOCK_ENGINE_PROC(
CreateAOTData, ([&](const FlutterEngineAOTDataSource* source,
FlutterEngineAOTData* data_out) {
create_aot_data_called = true;
source_type = source->type;
source_path = source->type == kFlutterEngineAOTDataSourceTypeDllPath
? source->dll_path
: source->elf_path;
*data_out = reinterpret_cast<FlutterEngineAOTData>(1);
return kSuccess;
}));
modifier.embedder_api().CollectAOTData = MOCK_ENGINE_PROC(
CollectAOTData, [](FlutterEngineAOTData data) { return kSuccess; });

bool run_called = false;
modifier.embedder_api().Run = MOCK_ENGINE_PROC(
Run, ([&run_called](size_t version, const FlutterProjectArgs* args,
void* user_data,
FLUTTER_API_SYMBOL(FlutterEngine)* engine_out) {
run_called = true;
*engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(1);

// The engine must be launched with the created AOT data.
EXPECT_EQ(args->aot_data, reinterpret_cast<FlutterEngineAOTData>(1));
return kSuccess;
}));

// It should send locale info.
modifier.embedder_api().UpdateLocales = MOCK_ENGINE_PROC(
UpdateLocales, ([](auto engine, const FlutterLocale** locales,
size_t locales_count) { return kSuccess; }));

// Ensure that deallocation doesn't call the actual Shutdown with the bogus
// engine pointer that the overridden Run returned.
modifier.embedder_api().Shutdown = [](auto engine) { return kSuccess; };

EXPECT_TRUE(engine->Run());

EXPECT_TRUE(run_called);
EXPECT_TRUE(create_aot_data_called);
#if FML_ARCH_CPU_X86_64
EXPECT_EQ(source_type, kFlutterEngineAOTDataSourceTypeDllPath);
#else
EXPECT_EQ(source_type, kFlutterEngineAOTDataSourceTypeElfPath);
#endif
EXPECT_EQ(source_path, fml::PathToUtf8(aot_library_path));
}

TEST_F(FlutterWindowsEngineTest, RunDoesExpectedInitialization) {
FlutterWindowsEngineBuilder builder{GetContext()};
builder.AddDartEntrypointArgument("arg1");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ void FlutterWindowsEngineBuilder::SetDartEntrypoint(std::string entrypoint) {
properties_.dart_entrypoint = dart_entrypoint_.c_str();
}

void FlutterWindowsEngineBuilder::SetAotLibraryPath(std::wstring path) {
aot_library_path_ = std::move(path);
properties_.aot_library_path = aot_library_path_.c_str();
}

void FlutterWindowsEngineBuilder::AddDartEntrypointArgument(std::string arg) {
dart_entrypoint_arguments_.emplace_back(std::move(arg));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class FlutterWindowsEngineBuilder {

void SetDartEntrypoint(std::string entrypoint);

void SetAotLibraryPath(std::wstring path);

void AddDartEntrypointArgument(std::string arg);

void SetSwitches(std::vector<std::string> switches);
Expand All @@ -35,6 +37,7 @@ class FlutterWindowsEngineBuilder {
WindowsTestContext& context_;
FlutterDesktopEngineProperties properties_ = {};
std::string dart_entrypoint_;
std::wstring aot_library_path_;
std::vector<std::string> dart_entrypoint_arguments_;
std::vector<std::string> switches_;
std::shared_ptr<WindowsProcTable> windows_proc_table_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ class ArtifactPublisher {
// with no prefix.
final baseDestination = name.contains('flutter.io')
// android
? ''
? './'
: 'flutter_infra_release/flutter/\${{ steps.engine_content_hash.outputs.value }}/${artifact.outputPath}';
_writeR2UploadStep(
steps,
Expand Down Expand Up @@ -750,7 +750,7 @@ void _writeArtifactTestJobs(
run.writeln(r'echo "value=${engine_content_hash}" >> $GITHUB_OUTPUT');
}
{
final step = steps.beginMap('name', 'Copy g lient file');
final step = steps.beginMap('name', 'Copy gclient file');
final run = step.beginMap('run', '|');
final gclientFile = gclientFileFor[job.gclient];
if (gclientFile == null) {
Expand Down
9 changes: 9 additions & 0 deletions packages/flutter_tools/analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ analyzer:
- linux/**
include: ../analysis_options.yaml

plugins:
flutter_analyzer_plugin:
path: ../../dev/flutter_analyzer_plugin
diagnostics:
avoid_future_catch_error: true
dependency_overrides:
analysis_server_plugin: ^0.3.22

linter:
rules:
avoid_catches_without_on_clauses: true
Expand All @@ -21,3 +29,4 @@ linter:
public_member_api_docs: false # Tool does not have any public API.
unawaited_futures: true
unintended_html_in_doc_comment: true
use_null_aware_elements: true
36 changes: 25 additions & 11 deletions packages/flutter_tools/bin/fuchsia_tester.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/context/tool_dependencies.dart';
import 'package:flutter_tools/src/context_runner.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
Expand Down Expand Up @@ -116,6 +117,14 @@ Future<void> run(List<String> args) async {
// TODO(tvolkert): Remove once flutter_tester no longer looks for this.
globals.fs.link(sdkRootDest.childFile('platform.dill').path).createSync('platform_strong.dill');

final ToolDependencies dependencies = await ToolDependencies.bootstrap(
artifacts: globals.artifacts,
fs: globals.fs,
logger: globals.logger,
platform: globals.platform,
processManager: globals.processManager,
);

Directory? testDirectory;
CoverageCollector? collector;
if (argResults['coverage'] as bool? ?? false) {
Expand All @@ -128,9 +137,10 @@ Future<void> run(List<String> args) async {
globals.fs.path.absolute(argResults[_kOptionPackages] as String),
);
collector = CoverageCollector(
packagesPath: packagesPath,
libraryNames: libraryNames,
packagesPath: packagesPath,
resolver: await CoverageCollector.getResolver(packagesPath),
toolContext: dependencies.toolContext,
);
if (!argResults.options.contains(_kOptionTestDirectory)) {
throwToolExit('Use of --coverage requires setting --test-directory');
Expand Down Expand Up @@ -158,18 +168,22 @@ Future<void> run(List<String> args) async {
globals.fs.path.absolute(argResults[_kOptionPackages] as String),
),
);
exitCode = await const FlutterTestRunner().runTests(
final debuggingOptions = DebuggingOptions.enabled(buildInfo);
final testRunner = FlutterTestRunner(toolContext: dependencies.toolContext);
exitCode = await testRunner.runTests(
const TestWrapper(),
tests.keys.map(Uri.file).toList(),
debuggingOptions: DebuggingOptions.enabled(buildInfo),
buildInfo: buildInfo,
watcher: collector,
enableVmService: collector != null,
precompiledDillFiles: tests,
concurrency: math.max(1, globals.platform.numberOfProcessors - 2),
icudtlPath: globals.fs.path.absolute(argResults[_kOptionIcudtl] as String),
coverageDirectory: coverageDirectory,
nativeAssetsBuilder: const TestCompilerNativeAssetsBuilderImpl(),
TestExecutionSpecification(
debuggingOptions: debuggingOptions,
buildInfo: buildInfo,
watcher: collector,
enableVmService: collector != null,
precompiledDillFiles: tests,
concurrency: math.max(1, globals.platform.numberOfProcessors - 2),
icudtlPath: globals.fs.path.absolute(argResults[_kOptionIcudtl] as String),
coverageDirectory: coverageDirectory,
nativeAssetsBuilder: const TestCompilerNativeAssetsBuilderImpl(),
),
);

if (collector != null) {
Expand Down
25 changes: 14 additions & 11 deletions packages/flutter_tools/bin/podhelper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ def flutter_additional_ios_build_settings(target)
# ARC code targeting iOS 8 does not build on Xcode 14.3. Force to at least iOS 9.
build_configuration.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '9.0' if force_to_arc_supported_min

# Suppress warning/error when pod supports a version lower than the minimum supported by Xcode.
# Xcode 27+ produces an error while previous versions produced a warning.
# When it's just a warning, it's harmless but confusing--it's not a bad thing for dependencies to support a lower version.
# When deleted, the deployment version will inherit from the higher version derived from the 'Runner' target.
# If the pod only supports a higher version, do not delete to correctly produce an error.
build_configuration.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' if inherit_deployment_target

# Skip other updates if it does not depend on Flutter (including transitive dependency)
next unless depends_on_flutter(target, 'Flutter')

Expand All @@ -103,11 +110,6 @@ def flutter_additional_ios_build_settings(target)
build_configuration.build_settings['OTHER_LDFLAGS'] = '$(inherited) -framework Flutter'

build_configuration.build_settings['CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER'] = 'NO'
# Suppress warning when pod supports a version lower than the minimum supported by Xcode (Xcode 12 - iOS 9).
# This warning is harmless but confusing--it's not a bad thing for dependencies to support a lower version.
# When deleted, the deployment version will inherit from the higher version derived from the 'Runner' target.
# If the pod only supports a higher version, do not delete to correctly produce an error.
build_configuration.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' if inherit_deployment_target

# Override legacy Xcode 11 style VALID_ARCHS[sdk=iphonesimulator*]=x86_64 and prefer Xcode 12 EXCLUDED_ARCHS.
build_configuration.build_settings['VALID_ARCHS[sdk=iphonesimulator*]'] = '$(ARCHS_STANDARD)'
Expand All @@ -128,8 +130,9 @@ def flutter_additional_macos_build_settings(target)
(deployment_target_major.to_i < 10) ||
(deployment_target_major.to_i == 10 && deployment_target_minor.to_i < 11)

# Suppress warning when pod supports a version lower than the minimum supported by the latest stable version of Xcode (currently 12.0).
# This warning is harmless but confusing--it's not a bad thing for dependencies to support a lower version.
# Suppress warning/error when pod supports a version lower than the minimum supported by the latest stable version of Xcode (currently 12.0).
# Xcode 27+ produces an error while previous versions produced a warning.
# When it's just a warning, it's harmless but confusing--it's not a bad thing for dependencies to support a lower version.
inherit_deployment_target = !target.deployment_target.blank? &&
(deployment_target_major.to_i < 12)

Expand All @@ -152,6 +155,10 @@ def flutter_additional_macos_build_settings(target)
# ARC code targeting macOS 10.10 does not build on Xcode 14.3. Force to at least macOS 10.11.
build_configuration.build_settings['MACOSX_DEPLOYMENT_TARGET'] = '10.11' if force_to_arc_supported_min

# When deleted, the deployment version will inherit from the higher version derived from the 'Runner' target.
# If the pod only supports a higher version, do not delete to correctly produce an error.
build_configuration.build_settings.delete 'MACOSX_DEPLOYMENT_TARGET' if inherit_deployment_target

# Skip other updates if it does not depend on Flutter (including transitive dependency)
next unless depends_on_flutter(target, 'FlutterMacOS')

Expand All @@ -167,10 +174,6 @@ def flutter_additional_macos_build_settings(target)
end
end

# When deleted, the deployment version will inherit from the higher version derived from the 'Runner' target.
# If the pod only supports a higher version, do not delete to correctly produce an error.
build_configuration.build_settings.delete 'MACOSX_DEPLOYMENT_TARGET' if inherit_deployment_target

# Avoid error about Pods-Runner not supporting provisioning profiles.
# Framework signing is handled at the app layer, not per framework, so disallow individual signing.
build_configuration.build_settings.delete 'EXPANDED_CODE_SIGN_IDENTITY'
Expand Down
Loading
Loading