[flutter_tools] support --split-debug-info option in android builds (#49650)
diff --git a/packages/flutter_tools/bin/macos_assemble.sh b/packages/flutter_tools/bin/macos_assemble.sh
index c923cc6..b821c96 100755
--- a/packages/flutter_tools/bin/macos_assemble.sh
+++ b/packages/flutter_tools/bin/macos_assemble.sh
@@ -37,6 +37,12 @@
flutter_engine_flag="--local-engine-src-path=${FLUTTER_ENGINE}"
fi
+# Provide location to split debug info
+split_debug_info_option=""
+if [[ -n "$SPLIT_DEBUG_INFO" ]]; then
+ split_debug_info_option="-dSplitDebugInfo=${SPLIT_DEBUG_INFO}"
+fi
+
# Set the build mode
build_mode="$(echo "${FLUTTER_BUILD_MODE:-${CONFIGURATION}}" | tr "[:upper:]" "[:lower:]")"
@@ -75,7 +81,8 @@
-dTargetPlatform=darwin-x64 \
-dTargetFile="${target_path}" \
-dBuildMode="${build_mode}" \
- -dFontSubset="${icon_tree_shaker_flag}" \
+ "${split_debug_info_option}" \
+ -dFontSubset="${icon_tree_shaker_flag}" \
--build-inputs="${build_inputs_path}" \
--build-outputs="${build_outputs_path}" \
--output="${ephemeral_dir}" \
diff --git a/packages/flutter_tools/gradle/flutter.gradle b/packages/flutter_tools/gradle/flutter.gradle
index 69a63df..ee764b9 100644
--- a/packages/flutter_tools/gradle/flutter.gradle
+++ b/packages/flutter_tools/gradle/flutter.gradle
@@ -603,6 +603,10 @@
if (project.hasProperty('extra-gen-snapshot-options')) {
extraGenSnapshotOptionsValue = project.property('extra-gen-snapshot-options')
}
+ String splitDebugInfoValue = null
+ if (project.hasProperty('split-debug-info')) {
+ splitDebugInfoValue = project.property('split-debug-info')
+ }
Boolean treeShakeIconsOptionsValue = false
if (project.hasProperty('tree-shake-icons')) {
treeShakeIconsOptionsValue = project.property('tree-shake-icons').toBoolean()
@@ -641,6 +645,7 @@
intermediateDir project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}/")
extraFrontEndOptions extraFrontEndOptionsValue
extraGenSnapshotOptions extraGenSnapshotOptionsValue
+ splitDebugInfo splitDebugInfoValue
treeShakeIcons treeShakeIconsOptionsValue
}
File libJar = project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}/libs.jar")
@@ -775,6 +780,8 @@
@Optional @Input
String extraGenSnapshotOptions
@Optional @Input
+ String splitDebugInfo
+ @Optional @Input
Boolean treeShakeIcons
@OutputFiles
@@ -832,6 +839,9 @@
if (extraFrontEndOptions != null) {
args "-dExtraFrontEndOptions=${extraFrontEndOptions}"
}
+ if (splitDebugInfo != null) {
+ args "-dSplitDebugInfo=${splitDebugInfo}"
+ }
if (treeShakeIcons == true) {
args "-dTreeShakeIcons=true"
}
diff --git a/packages/flutter_tools/lib/src/android/gradle.dart b/packages/flutter_tools/lib/src/android/gradle.dart
index 74bb007..9d386d5 100644
--- a/packages/flutter_tools/lib/src/android/gradle.dart
+++ b/packages/flutter_tools/lib/src/android/gradle.dart
@@ -338,6 +338,9 @@
if (androidBuildInfo.fastStart) {
command.add('-Pfast-start=true');
}
+ if (androidBuildInfo.buildInfo.splitDebugInfoPath != null) {
+ command.add('-Psplit-debug-info=${androidBuildInfo.buildInfo.splitDebugInfoPath}');
+ }
if (androidBuildInfo.buildInfo.treeShakeIcons) {
command.add('-Ptree-shake-icons=true');
}
diff --git a/packages/flutter_tools/lib/src/aot.dart b/packages/flutter_tools/lib/src/aot.dart
index 24d3b84..c3c5d8b 100644
--- a/packages/flutter_tools/lib/src/aot.dart
+++ b/packages/flutter_tools/lib/src/aot.dart
@@ -92,6 +92,7 @@
extraGenSnapshotOptions: extraGenSnapshotOptions,
bitcode: bitcode,
quiet: quiet,
+ splitDebugInfo: null,
).then<int>((int buildExitCode) {
return buildExitCode;
});
@@ -128,6 +129,7 @@
outputPath: outputPath,
extraGenSnapshotOptions: extraGenSnapshotOptions,
bitcode: false,
+ splitDebugInfo: null,
);
if (snapshotExitCode != 0) {
status?.cancel();
diff --git a/packages/flutter_tools/lib/src/base/build.dart b/packages/flutter_tools/lib/src/base/build.dart
index 42bef53..370e750 100644
--- a/packages/flutter_tools/lib/src/base/build.dart
+++ b/packages/flutter_tools/lib/src/base/build.dart
@@ -94,6 +94,7 @@
DarwinArch darwinArch,
List<String> extraGenSnapshotOptions = const <String>[],
@required bool bitcode,
+ @required String splitDebugInfo,
bool quiet = false,
}) async {
if (bitcode && platform != TargetPlatform.ios) {
@@ -157,11 +158,25 @@
genSnapshotArgs.add('--no-use-integer-division');
}
+ // The name of the debug file must contain additonal information about
+ // the architecture, since a single build command may produce
+ // multiple debug files.
+ final String archName = getNameForTargetPlatform(platform, darwinArch: darwinArch);
+ final String debugFilename = 'app.$archName.symbols';
+ if (splitDebugInfo != null) {
+ globals.fs.directory(splitDebugInfo)
+ .createSync(recursive: true);
+ }
+
// Optimization arguments.
genSnapshotArgs.addAll(<String>[
// Faster async/await
'--no-causal-async-stacks',
'--lazy-async-stacks',
+ if (splitDebugInfo != null) ...<String>[
+ '--dwarf-stack-traces',
+ '--save-debugging-info=${globals.fs.path.join(splitDebugInfo, debugFilename)}'
+ ]
]);
genSnapshotArgs.add(mainPath);
diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart
index 3888954..edad71e 100644
--- a/packages/flutter_tools/lib/src/build_info.dart
+++ b/packages/flutter_tools/lib/src/build_info.dart
@@ -21,6 +21,7 @@
this.fileSystemScheme,
this.buildNumber,
this.buildName,
+ this.splitDebugInfoPath,
@required this.treeShakeIcons,
});
@@ -62,6 +63,11 @@
/// On Xcode builds it is used as CFBundleShortVersionString,
final String buildName;
+ /// An optional directory path to save debugging information from dwarf stack
+ /// traces. If null, stack trace information is not stripped from the
+ /// executable.
+ final String splitDebugInfoPath;
+
static const BuildInfo debug = BuildInfo(BuildMode.debug, null, treeShakeIcons: false);
static const BuildInfo profile = BuildInfo(BuildMode.profile, null, treeShakeIcons: kIconTreeShakerEnabledDefault);
static const BuildInfo jitRelease = BuildInfo(BuildMode.jitRelease, null, treeShakeIcons: kIconTreeShakerEnabledDefault);
@@ -392,7 +398,7 @@
return null;
}
-String getNameForTargetPlatform(TargetPlatform platform) {
+String getNameForTargetPlatform(TargetPlatform platform, {DarwinArch darwinArch}) {
switch (platform) {
case TargetPlatform.android_arm:
return 'android-arm';
@@ -403,6 +409,9 @@
case TargetPlatform.android_x86:
return 'android-x86';
case TargetPlatform.ios:
+ if (darwinArch != null) {
+ return 'ios-${getNameForDarwinArch(darwinArch)}';
+ }
return 'ios';
case TargetPlatform.darwin_x64:
return 'darwin-x64';
diff --git a/packages/flutter_tools/lib/src/build_system/targets/android.dart b/packages/flutter_tools/lib/src/build_system/targets/android.dart
index d2766cb..f7a8405 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/android.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/android.dart
@@ -204,6 +204,7 @@
Future<void> build(Environment environment) async {
final AOTSnapshotter snapshotter = AOTSnapshotter(reportTimings: false);
final Directory output = environment.buildDir.childDirectory(_androidAbiName);
+ final String splitDebugInfo = environment.defines[kSplitDebugInfo];
if (environment.defines[kBuildMode] == null) {
throw MissingDefineException(kBuildMode, 'aot_elf');
}
@@ -221,6 +222,7 @@
outputPath: output.path,
bitcode: false,
extraGenSnapshotOptions: extraGenSnapshotOptions,
+ splitDebugInfo: splitDebugInfo,
);
if (snapshotExitCode != 0) {
throw Exception('AOT snapshotter exited with code $snapshotExitCode');
diff --git a/packages/flutter_tools/lib/src/build_system/targets/dart.dart b/packages/flutter_tools/lib/src/build_system/targets/dart.dart
index 7e46db2..9a03afb 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/dart.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/dart.dart
@@ -41,6 +41,9 @@
/// This is expected to be a comma separated list of strings.
const String kExtraGenSnapshotOptions = 'ExtraGenSnapshotOptions';
+/// Whether to strip source code information out of release builds and where to save it.
+const String kSplitDebugInfo = 'SplitDebugInfo';
+
/// Alternative scheme for file URIs.
///
/// May be used along with [kFileSystemRoots] to support a multi-root
@@ -259,6 +262,7 @@
?? const <String>[];
final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
final TargetPlatform targetPlatform = getTargetPlatformForName(environment.defines[kTargetPlatform]);
+ final String saveDebuggingInformation = environment.defines[kSplitDebugInfo];
final int snapshotExitCode = await snapshotter.build(
platform: targetPlatform,
buildMode: buildMode,
@@ -267,6 +271,7 @@
outputPath: outputPath,
bitcode: false,
extraGenSnapshotOptions: extraGenSnapshotOptions,
+ splitDebugInfo: saveDebuggingInformation
);
if (snapshotExitCode != 0) {
throw Exception('AOT snapshotter exited with code $snapshotExitCode');
diff --git a/packages/flutter_tools/lib/src/build_system/targets/ios.dart b/packages/flutter_tools/lib/src/build_system/targets/ios.dart
index a25b1ef..e71258b 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart
@@ -38,6 +38,7 @@
final bool bitcode = environment.defines[kBitcodeFlag] == 'true';
final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
final TargetPlatform targetPlatform = getTargetPlatformForName(environment.defines[kTargetPlatform]);
+ final String splitDebugInfo = environment.defines[kSplitDebugInfo];
final List<DarwinArch> iosArchs = environment.defines[kIosArchs]
?.split(' ')
?.map(getIOSArchForName)
@@ -60,6 +61,7 @@
darwinArch: iosArch,
bitcode: bitcode,
quiet: true,
+ splitDebugInfo: splitDebugInfo,
));
}
final List<int> results = await Future.wait(pending);
diff --git a/packages/flutter_tools/lib/src/build_system/targets/macos.dart b/packages/flutter_tools/lib/src/build_system/targets/macos.dart
index 2eeba00..7368512 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/macos.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/macos.dart
@@ -200,6 +200,7 @@
if (buildMode == BuildMode.debug) {
throw Exception('precompiled macOS framework only supported in release/profile builds.');
}
+ final String splitDebugInfo = environment.defines[kSplitDebugInfo];
final int result = await AOTSnapshotter(reportTimings: false).build(
bitcode: false,
buildMode: buildMode,
@@ -208,6 +209,7 @@
platform: TargetPlatform.darwin_x64,
darwinArch: DarwinArch.x86_64,
packagesPath: environment.projectDir.childFile('.packages').path,
+ splitDebugInfo: splitDebugInfo,
);
if (result != 0) {
throw Exception('gen shapshot failed.');
diff --git a/packages/flutter_tools/lib/src/commands/build_apk.dart b/packages/flutter_tools/lib/src/commands/build_apk.dart
index 7e45e75..de01a1e 100644
--- a/packages/flutter_tools/lib/src/commands/build_apk.dart
+++ b/packages/flutter_tools/lib/src/commands/build_apk.dart
@@ -26,6 +26,7 @@
usesBuildNumberOption();
usesBuildNameOption();
addShrinkingFlag();
+ addSplitDebugInfoOption();
argParser
..addFlag('split-per-abi',
negatable: false,
diff --git a/packages/flutter_tools/lib/src/ios/xcodeproj.dart b/packages/flutter_tools/lib/src/ios/xcodeproj.dart
index e3410f1..f4c857d 100644
--- a/packages/flutter_tools/lib/src/ios/xcodeproj.dart
+++ b/packages/flutter_tools/lib/src/ios/xcodeproj.dart
@@ -167,6 +167,11 @@
xcodeBuildSettings.add('FLUTTER_TARGET=$targetOverride');
}
+ // This is an optional path to split debug info
+ if (buildInfo.splitDebugInfoPath != null) {
+ xcodeBuildSettings.add('SPLIT_DEBUG_INFO=${buildInfo.splitDebugInfoPath}');
+ }
+
// The build outputs directory, relative to FLUTTER_APPLICATION_PATH.
xcodeBuildSettings.add('FLUTTER_BUILD_DIR=${buildDirOverride ?? getBuildDirectory()}');
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart
index cb03804..68f932a 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -107,6 +107,7 @@
static const String kEnableExperiment = 'enable-experiment';
static const String kFileSystemRoot = 'filesystem-root';
static const String kFileSystemScheme = 'filesystem-scheme';
+ static const String kSplitDebugInfoOption = 'split-debug-info';
}
abstract class FlutterCommand extends Command<void> {
@@ -366,6 +367,20 @@
help: 'Build a JIT release version of your app${defaultToRelease ? ' (default mode)' : ''}.');
}
+ void addSplitDebugInfoOption() {
+ argParser.addOption(FlutterOptions.kSplitDebugInfoOption,
+ help: 'In a release build, this flag reduces application size by storing '
+ 'Dart program symbols in a separate file on the host rather than in the '
+ 'application. The value of the flag should be a directory where program '
+ 'symbol files can be stored for later use. These symbol files contain '
+ 'the information needed to symbolize Dart stack traces. For an app built '
+ 'with this flag, the \'flutter symbolize\' command with the right program '
+ 'symbol file is required to obtain a human readable stack trace. This '
+ 'command is tracked by https://github.com/flutter/flutter/issues/50206',
+ valueHelp: '/project-name/v1.2.3/',
+ );
+ }
+
void addTreeShakeIconsFlag() {
argParser.addFlag('tree-shake-icons',
negatable: true,
@@ -499,6 +514,9 @@
buildName: argParser.options.containsKey('build-name')
? stringArg('build-name')
: null,
+ splitDebugInfoPath: argParser.options.containsKey(FlutterOptions.kSplitDebugInfoOption)
+ ? stringArg(FlutterOptions.kSplitDebugInfoOption)
+ : null,
treeShakeIcons: argParser.options.containsKey('tree-shake-icons')
? boolArg('tree-shake-icons')
: kIconTreeShakerEnabledDefault,
diff --git a/packages/flutter_tools/templates/app/.gitignore.tmpl b/packages/flutter_tools/templates/app/.gitignore.tmpl
index ae1f183..78b3c2b 100644
--- a/packages/flutter_tools/templates/app/.gitignore.tmpl
+++ b/packages/flutter_tools/templates/app/.gitignore.tmpl
@@ -33,5 +33,8 @@
# Web related
lib/generated_plugin_registrant.dart
+# Symbolication related
+app.*.symbols
+
# Exceptions to above rules.
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
diff --git a/packages/flutter_tools/templates/module/common/.gitignore.tmpl b/packages/flutter_tools/templates/module/common/.gitignore.tmpl
index 86f4691..1607ae6 100644
--- a/packages/flutter_tools/templates/module/common/.gitignore.tmpl
+++ b/packages/flutter_tools/templates/module/common/.gitignore.tmpl
@@ -40,3 +40,6 @@
.ios/
.flutter-plugins
.flutter-plugins-dependencies
+
+# Symbolication related
+app.*.symbols
diff --git a/packages/flutter_tools/test/general.shard/base/build_test.dart b/packages/flutter_tools/test/general.shard/base/build_test.dart
index b50555b..baa51ee 100644
--- a/packages/flutter_tools/test/general.shard/base/build_test.dart
+++ b/packages/flutter_tools/test/general.shard/base/build_test.dart
@@ -266,6 +266,7 @@
packagesPath: '.packages',
outputPath: outputPath,
bitcode: false,
+ splitDebugInfo: null,
), isNot(equals(0)));
}, overrides: contextOverrides);
@@ -278,6 +279,7 @@
packagesPath: '.packages',
outputPath: outputPath,
bitcode: false,
+ splitDebugInfo: null,
), isNot(0));
}, overrides: contextOverrides);
@@ -290,6 +292,7 @@
packagesPath: '.packages',
outputPath: outputPath,
bitcode: false,
+ splitDebugInfo: null,
), isNot(0));
}, overrides: contextOverrides);
@@ -316,6 +319,7 @@
outputPath: outputPath,
darwinArch: DarwinArch.armv7,
bitcode: true,
+ splitDebugInfo: null,
);
expect(genSnapshotExitCode, 0);
@@ -376,6 +380,7 @@
outputPath: outputPath,
darwinArch: DarwinArch.armv7,
bitcode: true,
+ splitDebugInfo: null,
);
expect(genSnapshotExitCode, 0);
@@ -435,6 +440,7 @@
outputPath: outputPath,
darwinArch: DarwinArch.armv7,
bitcode: false,
+ splitDebugInfo: null,
);
expect(genSnapshotExitCode, 0);
@@ -463,6 +469,61 @@
expect(assemblyFile.readAsStringSync().contains('.section __DWARF'), true);
}, overrides: contextOverrides);
+ testUsingContext('builds iOS armv7 profile AOT snapshot with dwarf stack traces', () async {
+ globals.fs.file('main.dill').writeAsStringSync('binary magic');
+
+ final String outputPath = globals.fs.path.join('build', 'foo');
+ globals.fs.directory(outputPath).createSync(recursive: true);
+
+ final String assembly = globals.fs.path.join(outputPath, 'snapshot_assembly.S');
+ genSnapshot.outputs = <String, String>{
+ assembly: 'blah blah\n.section __DWARF\nblah blah\n',
+ };
+ final String debugPath = globals.fs.path.join('foo', 'app.ios-armv7.symbols');
+
+ final RunResult successResult = RunResult(ProcessResult(1, 0, '', ''), <String>['command name', 'arguments...']);
+ when(mockXcode.cc(any)).thenAnswer((_) => Future<RunResult>.value(successResult));
+ when(mockXcode.clang(any)).thenAnswer((_) => Future<RunResult>.value(successResult));
+
+ final int genSnapshotExitCode = await snapshotter.build(
+ platform: TargetPlatform.ios,
+ buildMode: BuildMode.profile,
+ mainPath: 'main.dill',
+ packagesPath: '.packages',
+ outputPath: outputPath,
+ darwinArch: DarwinArch.armv7,
+ bitcode: false,
+ splitDebugInfo: 'foo',
+ );
+
+ expect(genSnapshotExitCode, 0);
+ expect(genSnapshot.callCount, 1);
+ expect(genSnapshot.snapshotType.platform, TargetPlatform.ios);
+ expect(genSnapshot.snapshotType.mode, BuildMode.profile);
+ expect(genSnapshot.additionalArgs, <String>[
+ '--deterministic',
+ '--snapshot_kind=app-aot-assembly',
+ '--assembly=$assembly',
+ '--strip',
+ '--no-sim-use-hardfp',
+ '--no-use-integer-division',
+ '--no-causal-async-stacks',
+ '--lazy-async-stacks',
+ '--dwarf-stack-traces',
+ '--save-debugging-info=$debugPath',
+ 'main.dill',
+ ]);
+ verifyNever(mockXcode.cc(argThat(contains('-fembed-bitcode'))));
+ verifyNever(mockXcode.clang(argThat(contains('-fembed-bitcode'))));
+
+ verify(mockXcode.cc(argThat(contains('-isysroot')))).called(1);
+ verify(mockXcode.clang(argThat(contains('-isysroot')))).called(1);
+
+ final File assemblyFile = globals.fs.file(assembly);
+ expect(assemblyFile.existsSync(), true);
+ expect(assemblyFile.readAsStringSync().contains('.section __DWARF'), true);
+ }, overrides: contextOverrides);
+
testUsingContext('builds iOS arm64 profile AOT snapshot', () async {
globals.fs.file('main.dill').writeAsStringSync('binary magic');
@@ -485,6 +546,7 @@
outputPath: outputPath,
darwinArch: DarwinArch.arm64,
bitcode: false,
+ splitDebugInfo: null,
);
expect(genSnapshotExitCode, 0);
@@ -524,6 +586,7 @@
outputPath: outputPath,
darwinArch: DarwinArch.armv7,
bitcode: false,
+ splitDebugInfo: null,
);
expect(genSnapshotExitCode, 0);
@@ -565,6 +628,7 @@
outputPath: outputPath,
darwinArch: DarwinArch.arm64,
bitcode: false,
+ splitDebugInfo: null,
);
expect(genSnapshotExitCode, 0);
@@ -595,6 +659,7 @@
packagesPath: '.packages',
outputPath: outputPath,
bitcode: false,
+ splitDebugInfo: null,
);
expect(genSnapshotExitCode, 0);
@@ -614,6 +679,42 @@
]);
}, overrides: contextOverrides);
+ testUsingContext('builds shared library for android-arm with dwarf stack traces', () async {
+ globals.fs.file('main.dill').writeAsStringSync('binary magic');
+
+ final String outputPath = globals.fs.path.join('build', 'foo');
+ final String debugPath = globals.fs.path.join('foo', 'app.android-arm.symbols');
+ globals.fs.directory(outputPath).createSync(recursive: true);
+
+ final int genSnapshotExitCode = await snapshotter.build(
+ platform: TargetPlatform.android_arm,
+ buildMode: BuildMode.release,
+ mainPath: 'main.dill',
+ packagesPath: '.packages',
+ outputPath: outputPath,
+ bitcode: false,
+ splitDebugInfo: 'foo',
+ );
+
+ expect(genSnapshotExitCode, 0);
+ expect(genSnapshot.callCount, 1);
+ expect(genSnapshot.snapshotType.platform, TargetPlatform.android_arm);
+ expect(genSnapshot.snapshotType.mode, BuildMode.release);
+ expect(genSnapshot.additionalArgs, <String>[
+ '--deterministic',
+ '--snapshot_kind=app-aot-elf',
+ '--elf=build/foo/app.so',
+ '--strip',
+ '--no-sim-use-hardfp',
+ '--no-use-integer-division',
+ '--no-causal-async-stacks',
+ '--lazy-async-stacks',
+ '--dwarf-stack-traces',
+ '--save-debugging-info=$debugPath',
+ 'main.dill',
+ ]);
+ }, overrides: contextOverrides);
+
testUsingContext('builds shared library for android-arm64', () async {
globals.fs.file('main.dill').writeAsStringSync('binary magic');
@@ -627,6 +728,7 @@
packagesPath: '.packages',
outputPath: outputPath,
bitcode: false,
+ splitDebugInfo: null,
);
expect(genSnapshotExitCode, 0);
@@ -665,6 +767,7 @@
packagesPath: '.packages',
outputPath: outputPath,
bitcode: false,
+ splitDebugInfo: null,
);
expect(genSnapshotExitCode, 0);
diff --git a/packages/flutter_tools/test/general.shard/build_info_test.dart b/packages/flutter_tools/test/general.shard/build_info_test.dart
index fcd28ee..5db5da7 100644
--- a/packages/flutter_tools/test/general.shard/build_info_test.dart
+++ b/packages/flutter_tools/test/general.shard/build_info_test.dart
@@ -78,4 +78,11 @@
expect(() => BuildMode.fromName('foo'), throwsArgumentError);
});
});
+
+ test('getNameForTargetPlatform on Darwin arches', () {
+ expect(getNameForTargetPlatform(TargetPlatform.ios, darwinArch: DarwinArch.arm64), 'ios-arm64');
+ expect(getNameForTargetPlatform(TargetPlatform.ios, darwinArch: DarwinArch.armv7), 'ios-armv7');
+ expect(getNameForTargetPlatform(TargetPlatform.ios, darwinArch: DarwinArch.x86_64), 'ios-x86_64');
+ expect(getNameForTargetPlatform(TargetPlatform.android), isNot(contains('ios')));
+ });
}
diff --git a/packages/flutter_tools/test/general.shard/commands/build_apk_test.dart b/packages/flutter_tools/test/general.shard/commands/build_apk_test.dart
index 31a6370..d467790 100644
--- a/packages/flutter_tools/test/general.shard/commands/build_apk_test.dart
+++ b/packages/flutter_tools/test/general.shard/commands/build_apk_test.dart
@@ -230,6 +230,35 @@
ProcessManager: () => mockProcessManager,
});
+ testUsingContext('--split-debug-info is enabled when an output directory is provided', () async {
+ final String projectPath = await createProject(tempDir,
+ arguments: <String>['--no-pub', '--template=app']);
+
+ await expectLater(() async {
+ await runBuildApkCommand(projectPath, arguments: <String>['--split-debug-info=${tempDir.path}']);
+ }, throwsToolExit(message: 'Gradle task assembleRelease failed with exit code 1'));
+
+ verify(mockProcessManager.start(
+ <String>[
+ gradlew,
+ '-q',
+ '-Ptarget=${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}',
+ '-Ptrack-widget-creation=true',
+ '-Pshrink=true',
+ '-Ptarget-platform=android-arm,android-arm64,android-x64',
+ '-Psplit-debug-info=${tempDir.path}',
+ 'assembleRelease',
+ ],
+ workingDirectory: anyNamed('workingDirectory'),
+ environment: anyNamed('environment'),
+ )).called(1);
+ },
+ overrides: <Type, Generator>{
+ AndroidSdk: () => mockAndroidSdk,
+ FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
+ ProcessManager: () => mockProcessManager,
+ });
+
testUsingContext('shrinking is disabled when --no-shrink is passed', () async {
final String projectPath = await createProject(tempDir,
arguments: <String>['--no-pub', '--template=app']);