Unverified Commit 08d079f6 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] wire up complete support for Dart obfuscation (#50509)

parent baa4b783
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter_devicelab/framework/apk_utils.dart';
import 'package:flutter_devicelab/framework/framework.dart';
import 'package:flutter_devicelab/framework/utils.dart';
import 'package:path/path.dart' as path;
Future<void> main() async {
await task(() async {
try {
bool foundProjectName = false;
await runProjectTest((FlutterProject flutterProject) async {
section('APK content for task assembleRelease with --obfuscate');
await inDirectory(flutterProject.rootPath, () async {
await flutter('build', options: <String>[
'apk',
'--target-platform=android-arm',
'--obfuscate',
'--split-debug-info=foo/',
]);
});
final String outputDirectory = path.join(
flutterProject.rootPath,
'build/app/outputs/apk/release/app-release.apk',
);
final Iterable<String> apkFiles = await getFilesInApk(outputDirectory);
checkCollectionContains<String>(<String>[
...flutterAssets,
...baseApkFiles,
'lib/armeabi-v7a/libapp.so',
], apkFiles);
// Verify that an identifier from the Dart project code is not present
// in the compiled binary.
await inDirectory(flutterProject.rootPath, () async {
await exec('unzip', <String>[outputDirectory]);
final String response = await eval(
'grep',
<String>[flutterProject.name, 'lib/armeabi-v7a/libapp.so'],
canFail: true,
);
if (response.trim().contains('matches')) {
foundProjectName = true;
}
});
});
if (foundProjectName) {
return TaskResult.failure('Found project name in obfuscated dart library');
}
return TaskResult.success(null);
} on TaskResult catch (taskResult) {
return taskResult;
} catch (e) {
return TaskResult.failure(e.toString());
}
});
}
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:io';
import 'package:flutter_devicelab/framework/apk_utils.dart';
import 'package:flutter_devicelab/framework/framework.dart';
import 'package:flutter_devicelab/framework/utils.dart';
import 'package:path/path.dart' as path;
Future<void> main() async {
await task(() async {
try {
bool foundProjectName = false;
await runProjectTest((FlutterProject flutterProject) async {
section('iOS Framework content with --obfuscate');
await inDirectory(flutterProject.rootPath, () async {
await flutter('build', options: <String>[
'ios',
'--release',
'--obfuscate',
'--split-debug-info=foo/',
]);
});
final String outputFramework = path.join(
flutterProject.rootPath,
'build/ios/iphoneos/Runner.app/Frameworks/App.framework/App',
);
if (!File(outputFramework).existsSync()) {
fail('Failed to produce expected output at $outputFramework');
}
// Verify that an identifier from the Dart project code is not present
// in the compiled binary.
await inDirectory(flutterProject.rootPath, () async {
final String response = await eval(
'grep',
<String>[flutterProject.name, outputFramework],
canFail: true,
);
if (response.trim().contains('matches')) {
foundProjectName = true;
}
});
});
if (foundProjectName) {
return TaskResult.failure('Found project name in obfuscated dart library');
}
return TaskResult.success(null);
} on TaskResult catch (taskResult) {
return taskResult;
} catch (e) {
return TaskResult.failure(e.toString());
}
});
}
......@@ -319,6 +319,13 @@ tasks:
stage: devicelab
required_agent_capabilities: ["mac/android"]
android_obfuscate_test:
description: >
Builds an obfuscated APK and verifies a dart identifier cannot be found
stage: devicelab
flaky: true
required_agent_capabilities: ["linux/android"]
complex_layout_semantics_perf:
description: >
Measures duration of building the initial semantics tree.
......@@ -390,6 +397,13 @@ tasks:
# iOS on-device tests
ios_obfuscate_test:
description: >
Builds an obfuscated APK and verifies a dart identifier cannot be found
stage: devicelab
flaky: true
required_agent_capabilities: ["mac/ios"]
tiles_scroll_perf_ios__timeline_summary:
description: >
Measures the runtime performance of the tiles tab in the Complex Layout sample app on iPhone 6.
......
......@@ -67,6 +67,11 @@ if [[ -n "$TREE_SHAKE_ICONS" ]]; then
icon_tree_shaker_flag="true"
fi
dart_obfuscation_flag="false"
if [[ -n "$DART_OBFUSCATION" ]]; then
dart_obfuscation_flag="true"
fi
RunCommand "${FLUTTER_ROOT}/bin/flutter" --suppress-analytics \
${verbose_flag} \
${flutter_engine_flag} \
......@@ -76,6 +81,7 @@ RunCommand "${FLUTTER_ROOT}/bin/flutter" --suppress-analytics \
-dTargetFile="${target_path}" \
-dBuildMode="${build_mode}" \
-dTreeShakeIcons="${icon_tree_shaker_flag}" \
-dDartObfuscation="${dart_obfuscation_flag}" \
-dSplitDebugInfo="${SPLIT_DEBUG_INFO}" \
--build-inputs="${build_inputs_path}" \
--build-outputs="${build_outputs_path}" \
......
......@@ -166,6 +166,11 @@ BuildApp() {
icon_tree_shaker_flag="true"
fi
dart_obfuscation_flag="false"
if [[ -n "$DART_OBFUSCATION" ]]; then
dart_obfuscation_flag="true"
fi
RunCommand "${FLUTTER_ROOT}/bin/flutter" \
${verbose_flag} \
${flutter_engine_flag} \
......@@ -179,6 +184,7 @@ BuildApp() {
-dSplitDebugInfo="${SPLIT_DEBUG_INFO}" \
-dTreeShakeIcons="${icon_tree_shaker_flag}" \
-dTrackWidgetCreation="${track_widget_creation_flag}" \
-dDartObfuscation="${dart_obfuscation_flag}" \
-dEnableBitcode="${bitcode_flag}" \
"${build_mode}_ios_bundle_flutter_assets"
......
......@@ -607,6 +607,10 @@ class FlutterPlugin implements Plugin<Project> {
if (project.hasProperty('split-debug-info')) {
splitDebugInfoValue = project.property('split-debug-info')
}
Boolean dartObfuscationValue = false
if (project.hasProperty('dart-obfuscation')) {
dartObfuscationValue = project.property('dart-obfuscation').toBoolean();
}
Boolean treeShakeIconsOptionsValue = false
if (project.hasProperty('tree-shake-icons')) {
treeShakeIconsOptionsValue = project.property('tree-shake-icons').toBoolean()
......@@ -647,6 +651,7 @@ class FlutterPlugin implements Plugin<Project> {
extraGenSnapshotOptions extraGenSnapshotOptionsValue
splitDebugInfo splitDebugInfoValue
treeShakeIcons treeShakeIconsOptionsValue
dartObfuscation dartObfuscationValue
doLast {
project.exec {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
......@@ -792,6 +797,8 @@ abstract class BaseFlutterTask extends DefaultTask {
String splitDebugInfo
@Optional @Input
Boolean treeShakeIcons
@Optional @Input
Boolean dartObfuscation
@OutputFiles
FileCollection getDependenciesFiles() {
......@@ -854,6 +861,9 @@ abstract class BaseFlutterTask extends DefaultTask {
if (treeShakeIcons == true) {
args "-dTreeShakeIcons=true"
}
if (dartObfuscation == true) {
args "-dDartObfuscation=true"
}
if (extraGenSnapshotOptions != null) {
args "--ExtraGenSnapshotOptions=${extraGenSnapshotOptions}"
}
......
......@@ -344,6 +344,9 @@ Future<void> buildGradleApp({
if (androidBuildInfo.buildInfo.treeShakeIcons) {
command.add('-Ptree-shake-icons=true');
}
if (androidBuildInfo.buildInfo.dartObfuscation) {
command.add('-Pdart-obfuscation=true');
}
command.add(assembleTask);
GradleHandledError detectedGradleError;
......
......@@ -93,6 +93,7 @@ class AotBuilder {
bitcode: bitcode,
quiet: quiet,
splitDebugInfo: null,
dartObfuscation: false,
).then<int>((int buildExitCode) {
return buildExitCode;
});
......@@ -130,6 +131,7 @@ class AotBuilder {
extraGenSnapshotOptions: extraGenSnapshotOptions,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: false,
);
if (snapshotExitCode != 0) {
status?.cancel();
......
......@@ -42,6 +42,16 @@ class GenSnapshot {
Artifact.genSnapshot, platform: snapshotType.platform, mode: snapshotType.mode);
}
/// Ignored warning messages from gen_snapshot.
static const Set<String> kIgnoredWarnings = <String>{
// --strip on elf snapshot.
'Warning: Generating ELF library without DWARF debugging information.',
// --strip on ios-assembly snapshot.
'Warning: Generating assembly code without DWARF debugging information.',
// A fun two-part message with spaces for obfuscation.
'Warning: This VM has been configured to obfuscate symbol information which violates the Dart standard.',
' See dartbug.com/30524 for more information.',
};
Future<int> run({
@required SnapshotType snapshotType,
DarwinArch darwinArch,
......@@ -59,18 +69,9 @@ class GenSnapshot {
snapshotterPath += '_' + getNameForDarwinArch(darwinArch);
}
StringConverter outputFilter;
if (additionalArgs.contains('--strip')) {
// Filter out gen_snapshot's warning message about stripping debug symbols
// from ELF library snapshots.
const String kStripWarning = 'Warning: Generating ELF library without DWARF debugging information.';
const String kAssemblyStripWarning = 'Warning: Generating assembly code without DWARF debugging information.';
outputFilter = (String line) => line != kStripWarning && line != kAssemblyStripWarning ? line : null;
}
return processUtils.stream(
<String>[snapshotterPath, ...args],
mapFunction: outputFilter,
mapFunction: (String line) => kIgnoredWarnings.contains(line) ? null : line,
);
}
}
......@@ -94,6 +95,7 @@ class AOTSnapshotter {
List<String> extraGenSnapshotOptions = const <String>[],
@required bool bitcode,
@required String splitDebugInfo,
@required bool dartObfuscation,
bool quiet = false,
}) async {
if (bitcode && platform != TargetPlatform.ios) {
......@@ -147,7 +149,8 @@ class AOTSnapshotter {
// multiple debug files.
final String archName = getNameForTargetPlatform(platform, darwinArch: darwinArch);
final String debugFilename = 'app.$archName.symbols';
if (splitDebugInfo?.isNotEmpty ?? false) {
final bool shouldSplitDebugInfo = splitDebugInfo?.isNotEmpty ?? false;
if (shouldSplitDebugInfo) {
globals.fs.directory(splitDebugInfo)
.createSync(recursive: true);
}
......@@ -157,10 +160,12 @@ class AOTSnapshotter {
// Faster async/await
'--no-causal-async-stacks',
'--lazy-async-stacks',
if (splitDebugInfo?.isNotEmpty ?? false) ...<String>[
if (shouldSplitDebugInfo) ...<String>[
'--dwarf-stack-traces',
'--save-debugging-info=${globals.fs.path.join(splitDebugInfo, debugFilename)}'
]
],
if (dartObfuscation)
'--obfuscate',
]);
genSnapshotArgs.add(mainPath);
......
......@@ -22,6 +22,7 @@ class BuildInfo {
this.buildNumber,
this.buildName,
this.splitDebugInfoPath,
this.dartObfuscation = false,
@required this.treeShakeIcons,
});
......@@ -68,6 +69,9 @@ class BuildInfo {
/// executable.
final String splitDebugInfoPath;
/// Whether to apply dart source code obfuscation.
final bool dartObfuscation;
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);
......
......@@ -222,6 +222,7 @@ class AndroidAot extends AotElfBase {
final List<String> extraGenSnapshotOptions = environment.defines[kExtraGenSnapshotOptions]?.split(',')
?? const <String>[];
final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
final bool dartObfuscation = environment.defines[kDartObfuscation] == 'true';
final int snapshotExitCode = await snapshotter.build(
platform: targetPlatform,
buildMode: buildMode,
......@@ -231,6 +232,7 @@ class AndroidAot extends AotElfBase {
bitcode: false,
extraGenSnapshotOptions: extraGenSnapshotOptions,
splitDebugInfo: splitDebugInfo,
dartObfuscation: dartObfuscation,
);
if (snapshotExitCode != 0) {
throw Exception('AOT snapshotter exited with code $snapshotExitCode');
......
......@@ -66,6 +66,9 @@ const String kDartDefines = 'DartDefines';
/// The other supported value is armv7, the 32-bit iOS architecture.
const String kIosArchs = 'IosArchs';
/// Whether to enable Dart obfuscation and where to save the symbol map.
const String kDartObfuscation = 'DartObfuscation';
/// Copies the pre-built flutter bundle.
// This is a one-off rule for implementing build bundle in terms of assemble.
class CopyFlutterBundle extends Target {
......@@ -270,7 +273,8 @@ abstract class AotElfBase extends Target {
?? const <String>[];
final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
final TargetPlatform targetPlatform = getTargetPlatformForName(environment.defines[kTargetPlatform]);
final String saveDebuggingInformation = environment.defines[kSplitDebugInfo];
final String splitDebugInfo = environment.defines[kSplitDebugInfo];
final bool dartObfuscation = environment.defines[kDartObfuscation] == 'true';
final int snapshotExitCode = await snapshotter.build(
platform: targetPlatform,
buildMode: buildMode,
......@@ -279,7 +283,8 @@ abstract class AotElfBase extends Target {
outputPath: outputPath,
bitcode: false,
extraGenSnapshotOptions: extraGenSnapshotOptions,
splitDebugInfo: saveDebuggingInformation
splitDebugInfo: splitDebugInfo,
dartObfuscation: dartObfuscation,
);
if (snapshotExitCode != 0) {
throw Exception('AOT snapshotter exited with code $snapshotExitCode');
......
......@@ -40,6 +40,7 @@ abstract class AotAssemblyBase extends Target {
final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
final TargetPlatform targetPlatform = getTargetPlatformForName(environment.defines[kTargetPlatform]);
final String splitDebugInfo = environment.defines[kSplitDebugInfo];
final bool dartObfuscation = environment.defines[kDartObfuscation] == 'true';
final List<DarwinArch> iosArchs = environment.defines[kIosArchs]
?.split(' ')
?.map(getIOSArchForName)
......@@ -63,6 +64,7 @@ abstract class AotAssemblyBase extends Target {
bitcode: bitcode,
quiet: true,
splitDebugInfo: splitDebugInfo,
dartObfuscation: dartObfuscation,
));
}
final List<int> results = await Future.wait(pending);
......
......@@ -201,6 +201,7 @@ class CompileMacOSFramework extends Target {
throw Exception('precompiled macOS framework only supported in release/profile builds.');
}
final String splitDebugInfo = environment.defines[kSplitDebugInfo];
final bool dartObfuscation = environment.defines[kDartObfuscation] == 'true';
final int result = await AOTSnapshotter(reportTimings: false).build(
bitcode: false,
buildMode: buildMode,
......@@ -210,6 +211,7 @@ class CompileMacOSFramework extends Target {
darwinArch: DarwinArch.x86_64,
packagesPath: environment.projectDir.childFile('.packages').path,
splitDebugInfo: splitDebugInfo,
dartObfuscation: dartObfuscation,
);
if (result != 0) {
throw Exception('gen shapshot failed.');
......
......@@ -27,6 +27,7 @@ class BuildApkCommand extends BuildSubCommand {
usesBuildNameOption();
addShrinkingFlag();
addSplitDebugInfoOption();
addDartObfuscationOption();
argParser
..addFlag('split-per-abi',
negatable: false,
......
......@@ -24,6 +24,8 @@ class BuildAppBundleCommand extends BuildSubCommand {
usesBuildNumberOption();
usesBuildNameOption();
addShrinkingFlag();
addSplitDebugInfoOption();
addDartObfuscationOption();
argParser
..addFlag('track-widget-creation', negatable: false, hide: !verboseHelp)
......
......@@ -26,6 +26,7 @@ class BuildIOSCommand extends BuildSubCommand {
usesPubOption();
usesBuildNumberOption();
usesBuildNameOption();
addDartObfuscationOption();
argParser
..addFlag('simulator',
help: 'Build for the iOS simulator instead of the device.',
......
......@@ -49,6 +49,8 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
usesFlavorOption();
usesPubOption();
usesDartDefines();
addSplitDebugInfoOption();
addDartObfuscationOption();
argParser
..addFlag('debug',
negatable: true,
......
......@@ -21,6 +21,7 @@ class BuildMacosCommand extends BuildSubCommand {
addSplitDebugInfoOption();
usesTargetOption();
addBuildModeFlags();
addDartObfuscationOption();
}
@override
......
......@@ -172,6 +172,11 @@ List<String> _xcodeBuildSettingsLines({
xcodeBuildSettings.add('SPLIT_DEBUG_INFO=${buildInfo.splitDebugInfoPath}');
}
// This is an optional path to obfuscate and output a mapping.
if (buildInfo.dartObfuscation) {
xcodeBuildSettings.add('DART_OBFUSCATION=true');
}
// The build outputs directory, relative to FLUTTER_APPLICATION_PATH.
xcodeBuildSettings.add('FLUTTER_BUILD_DIR=${buildDirOverride ?? getBuildDirectory()}');
......
......@@ -108,6 +108,7 @@ class FlutterOptions {
static const String kFileSystemRoot = 'filesystem-root';
static const String kFileSystemScheme = 'filesystem-scheme';
static const String kSplitDebugInfoOption = 'split-debug-info';
static const String kDartObfuscationOption = 'obfuscate';
}
abstract class FlutterCommand extends Command<void> {
......@@ -393,6 +394,18 @@ abstract class FlutterCommand extends Command<void> {
);
}
void addDartObfuscationOption() {
argParser.addFlag(FlutterOptions.kDartObfuscationOption,
help: 'In a release build, this flag removes identifiers and replaces them '
'with randomized values for the purposes of source code obfuscation. This '
'flag must always be combined with "--split-debug-info" option, the '
'mapping between the values and the original identifiers is stored in the '
'symbol map created in the specified directory. 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.',
);
}
void addTreeShakeIconsFlag() {
argParser.addFlag('tree-shake-icons',
negatable: true,
......@@ -483,6 +496,10 @@ abstract class FlutterCommand extends Command<void> {
);
}
/// Compute the [BuildInfo] for the current flutter command.
///
/// Throws a [ToolExit] if the current set of options is not compatible with
/// eachother.
BuildInfo getBuildInfo() {
final bool trackWidgetCreation = argParser.options.containsKey('track-widget-creation') &&
boolArg('track-widget-creation');
......@@ -507,6 +524,20 @@ abstract class FlutterCommand extends Command<void> {
}
}
final bool dartObfuscation = argParser.options.containsKey(FlutterOptions.kDartObfuscationOption)
&& boolArg(FlutterOptions.kDartObfuscationOption);
final String splitDebugInfoPath = argParser.options.containsKey(FlutterOptions.kSplitDebugInfoOption)
? stringArg(FlutterOptions.kSplitDebugInfoOption)
: null;
if (dartObfuscation && (splitDebugInfoPath == null || splitDebugInfoPath.isEmpty)) {
throwToolExit(
'"--${FlutterOptions.kDartObfuscationOption}" can only be used in '
'combination with "--${FlutterOptions.kSplitDebugInfoOption}"',
);
}
return BuildInfo(getBuildMode(),
argParser.options.containsKey('flavor')
? stringArg('flavor')
......@@ -526,12 +557,11 @@ abstract class FlutterCommand extends Command<void> {
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,
splitDebugInfoPath: splitDebugInfoPath,
dartObfuscation: dartObfuscation,
);
}
......
......@@ -36,5 +36,8 @@ lib/generated_plugin_registrant.dart
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Exceptions to above rules.
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
......@@ -43,3 +43,6 @@ build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:args/command_runner.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import '../../src/common.dart';
import '../../src/context.dart';
void main() {
testUsingContext('obfuscate requires split-debug-info', () {
final FakeBuildCommand command = FakeBuildCommand();
final CommandRunner<void> commandRunner = createTestCommandRunner(command);
expect(() => commandRunner.run(<String>[
'build',
'--obfuscate',
]), throwsA(isA<ToolExit>()));
});
}
class FakeBuildCommand extends FlutterCommand {
FakeBuildCommand() {
addSplitDebugInfoOption();
addDartObfuscationOption();
}
@override
String get description => throw UnimplementedError();
@override
String get name => 'build';
@override
Future<FlutterCommandResult> runCommand() async {
getBuildInfo();
return FlutterCommandResult.success();
}
}
......@@ -267,6 +267,7 @@ void main() {
outputPath: outputPath,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: false,
), isNot(equals(0)));
}, overrides: contextOverrides);
......@@ -280,6 +281,7 @@ void main() {
outputPath: outputPath,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: false,
), isNot(0));
}, overrides: contextOverrides);
......@@ -293,6 +295,7 @@ void main() {
outputPath: outputPath,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: false,
), isNot(0));
}, overrides: contextOverrides);
......@@ -320,6 +323,7 @@ void main() {
darwinArch: DarwinArch.armv7,
bitcode: true,
splitDebugInfo: null,
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
......@@ -381,6 +385,7 @@ void main() {
darwinArch: DarwinArch.armv7,
bitcode: true,
splitDebugInfo: null,
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
......@@ -441,6 +446,7 @@ void main() {
darwinArch: DarwinArch.armv7,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
......@@ -469,7 +475,7 @@ void main() {
expect(assemblyFile.readAsStringSync().contains('.section __DWARF'), true);
}, overrides: contextOverrides);
testUsingContext('builds iOS armv7 profile AOT snapshot with dwarf stack traces', () async {
testUsingContext('builds iOS armv7 profile AOT snapshot with dwarStackTraces', () async {
globals.fs.file('main.dill').writeAsStringSync('binary magic');
final String outputPath = globals.fs.path.join('build', 'foo');
......@@ -494,6 +500,7 @@ void main() {
darwinArch: DarwinArch.armv7,
bitcode: false,
splitDebugInfo: 'foo',
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
......@@ -524,6 +531,60 @@ void main() {
expect(assemblyFile.readAsStringSync().contains('.section __DWARF'), true);
}, overrides: contextOverrides);
testUsingContext('builds iOS armv7 profile AOT snapshot with obfuscate', () 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 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: null,
dartObfuscation: true,
);
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',
'--obfuscate',
'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');
......@@ -547,6 +608,7 @@ void main() {
darwinArch: DarwinArch.arm64,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
......@@ -587,6 +649,7 @@ void main() {
darwinArch: DarwinArch.armv7,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
......@@ -629,6 +692,7 @@ void main() {
darwinArch: DarwinArch.arm64,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
......@@ -660,6 +724,7 @@ void main() {
outputPath: outputPath,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
......@@ -694,6 +759,7 @@ void main() {
outputPath: outputPath,
bitcode: false,
splitDebugInfo: 'foo',
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
......@@ -715,6 +781,41 @@ void main() {
]);
}, overrides: contextOverrides);
testUsingContext('builds shared library for android-arm with obfuscate', () 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 int genSnapshotExitCode = await snapshotter.build(
platform: TargetPlatform.android_arm,
buildMode: BuildMode.release,
mainPath: 'main.dill',
packagesPath: '.packages',
outputPath: outputPath,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: true,
);
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',
'--obfuscate',
'main.dill',
]);
}, overrides: contextOverrides);
testUsingContext('builds shared library for android-arm without dwarf stack traces due to empty string', () async {
globals.fs.file('main.dill').writeAsStringSync('binary magic');
......@@ -729,6 +830,7 @@ void main() {
outputPath: outputPath,
bitcode: false,
splitDebugInfo: '',
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
......@@ -762,6 +864,7 @@ void main() {
outputPath: outputPath,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
......@@ -801,6 +904,7 @@ void main() {
outputPath: outputPath,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment