Unverified Commit ec58182b authored by James D. Lin's avatar James D. Lin Committed by GitHub

[flutter tools] Make SizeAnalyzer support .apk files that don't use libapp.so (#63250)

parent 25de9419
......@@ -17,11 +17,14 @@ class SizeAnalyzer {
@required this.fileSystem,
@required this.logger,
@required this.processUtils,
this.appFilenamePattern = 'libapp.so',
});
final FileSystem fileSystem;
final Logger logger;
final ProcessUtils processUtils;
final Pattern appFilenamePattern;
String _appFilename;
static const String aotSnapshotFileName = 'aot-snapshot.json';
......@@ -29,7 +32,7 @@ class SizeAnalyzer {
/// Analyzes [apk] and [aotSnapshot] to output a [Map] object that includes
/// the breakdown of the both files, where the breakdown of [aotSnapshot] is placed
/// under 'lib/arm64-v8a/libapp.so'.
/// under 'lib/arm64-v8a/$_appFilename'.
///
/// The [aotSnapshot] can be either instruction sizes snapshot or v8 snapshot.
Future<Map<String, dynamic>> analyzeApkSizeAndAotSnapshot({
......@@ -78,7 +81,7 @@ class SizeAnalyzer {
byteSize: firstLevelPath.byteSize,
level: 1,
);
// Print the expansion of lib directory to show more info for libapp.so.
// Print the expansion of lib directory to show more info for `appFilename`.
if (firstLevelPath.name == 'lib') {
_printLibChildrenPaths(firstLevelPath, '', aotSnapshotJsonRoot);
}
......@@ -91,9 +94,10 @@ class SizeAnalyzer {
apkAnalysisJson['type'] = 'apk';
// TODO(peterdjlee): Add aot snapshot for all platforms.
assert(_appFilename != null);
apkAnalysisJson = _addAotSnapshotDataToApkAnalysis(
apkAnalysisJson: apkAnalysisJson,
path: 'lib/arm64-v8a/libapp.so (Dart AOT)'.split('/'), // Pass in a list of paths by splitting with '/'.
path: 'lib/arm64-v8a/$_appFilename (Dart AOT)'.split('/'), // Pass in a list of paths by splitting with '/'.
aotSnapshotJson: processedAotSnapshotJson,
);
......@@ -137,9 +141,10 @@ class SizeAnalyzer {
if (childWithPathAsName == null) {
childWithPathAsName = _SymbolNode(path);
if (path.endsWith('libapp.so')) {
if (matchesPattern(path, pattern: appFilenamePattern) != null) {
_appFilename = path;
childWithPathAsName.name += ' (Dart AOT)';
} else if (path.endsWith('libflutter.so')) {
} else if (path == 'libflutter.so') {
childWithPathAsName.name += ' (Flutter Engine)';
}
currentNode.addChild(childWithPathAsName);
......@@ -155,7 +160,7 @@ class SizeAnalyzer {
/// Prints all children paths for the lib/ directory in an APK.
///
/// A brief summary of aot snapshot is printed under 'lib/arm64-v8a/libapp.so'.
/// A brief summary of aot snapshot is printed under 'lib/arm64-v8a/$_appFilename'.
void _printLibChildrenPaths(
_SymbolNode currentNode,
String totalPath,
......@@ -163,7 +168,9 @@ class SizeAnalyzer {
) {
totalPath += currentNode.name;
if (currentNode.children.isNotEmpty && !currentNode.name.contains('libapp.so')) {
assert(_appFilename != null);
if (currentNode.children.isNotEmpty
&& currentNode.name != '$_appFilename (Dart AOT)') {
for (final _SymbolNode child in currentNode.children) {
_printLibChildrenPaths(child, '$totalPath/', aotSnapshotJsonRoot);
}
......@@ -172,8 +179,8 @@ class SizeAnalyzer {
_printEntitySize(totalPath, byteSize: currentNode.byteSize, level: 2);
// We picked this file because arm64-v8a is likely the most popular
// architecture. ther architecture sizes should be similar.
const String libappPath = 'lib/arm64-v8a/libapp.so';
// architecture. Other architecture sizes should be similar.
final String libappPath = 'lib/arm64-v8a/$_appFilename';
// TODO(peterdjlee): Analyze aot size for all platforms.
if (totalPath.contains(libappPath)) {
_printAotSnapshotSummary(aotSnapshotJsonRoot);
......@@ -368,3 +375,10 @@ class _SymbolNode {
return json;
}
}
/// Matches `pattern` against the entirety of `string`.
@visibleForTesting
Match matchesPattern(String string, {@required Pattern pattern}) {
final Match match = pattern.matchAsPrefix(string);
return (match != null && match.end == string.length) ? match : null;
}
......@@ -602,8 +602,8 @@ abstract class FlutterCommand extends Command<void> {
argParser.addFlag(
FlutterOptions.kAnalyzeSize,
defaultsTo: false,
help: 'Whether to produce additonal profile information for artifact output size. '
'This flag is only support on release builds on macOS/Linux hosts.'
help: 'Whether to produce additional profile information for artifact output size. '
'This flag is only supported on release builds on macOS/Linux hosts.'
);
}
......
......@@ -26,7 +26,7 @@ Length Method Size Cmpr Date Time CRC-32 Name
11708 Defl:N 2592 78% 00-00-1980 00:00 07733eef AndroidManifest.xml
1399 Defl:N 1092 22% 00-00-1980 00:00 f53d952a META-INF/CERT.RSA
46298 Defl:N 14530 69% 00-00-1980 00:00 17df02b8 META-INF/CERT.SF
46298 Defl:N 14530 69% 00-00-1980 00:00 17df02b8 lib/arm64-v8a/libapp.so
46298 Defl:N 14530 69% 00-00-1980 00:00 17df02b8 lib/arm64-v8a/libxyzzyapp.so
46298 Defl:N 14530 69% 00-00-1980 00:00 17df02b8 lib/arm64-v8a/libflutter.so
''',
);
......@@ -70,6 +70,17 @@ void main() {
processManager = FakeProcessManager.list(<FakeCommand>[unzipCommmand]);
});
test('matchesPattern matches only entire strings', () {
expect(matchesPattern('', pattern: ''), isNotNull);
expect(matchesPattern('', pattern: 'foo'), null);
expect(matchesPattern('foo', pattern: ''), null);
expect(matchesPattern('foo', pattern: 'foo'), isNotNull);
expect(matchesPattern('foo', pattern: 'foobar'), null);
expect(matchesPattern('foobar', pattern: 'foo'), null);
expect(matchesPattern('foobar', pattern: RegExp(r'.*b.*')), isNotNull);
expect(matchesPattern('foobar', pattern: RegExp(r'.*b')), null);
});
test('builds APK analysis correctly', () async {
final SizeAnalyzer sizeAnalyzer = SizeAnalyzer(
fileSystem: fileSystem,
......@@ -78,6 +89,7 @@ void main() {
processManager: processManager,
logger: logger,
),
appFilenamePattern: RegExp(r'lib.*app\.so'),
);
final File apk = fileSystem.file('test.apk')..createSync();
......@@ -109,7 +121,7 @@ void main() {
expect(arm64Map['n'], equals('arm64-v8a'));
expect(arm64Map['value'], equals(29060));
final Map<String, dynamic> libAppMap = arm64Map['children'][0] as Map<String, dynamic>;
expect(libAppMap['n'], equals('libapp.so (Dart AOT)'));
expect(libAppMap['n'], equals('libxyzzyapp.so (Dart AOT)'));
expect(libAppMap['value'], equals(14530));
expect(libAppMap['children'].length, equals(3));
final Map<String, dynamic> internalMap = libAppMap['children'][0] as Map<String, dynamic>;
......@@ -140,6 +152,7 @@ void main() {
processManager: processManager,
logger: logger,
),
appFilenamePattern: RegExp(r'lib.*app\.so'),
);
final File apk = fileSystem.file('test.apk')..createSync();
......@@ -155,7 +168,7 @@ void main() {
' AndroidManifest.xml 3 KB',
' META-INF 15 KB',
' lib 28 KB',
' lib/arm64-v8a/libapp.so (Dart AOT) 14 KB',
' lib/arm64-v8a/libxyzzyapp.so (Dart AOT) 14 KB',
' Dart AOT symbols accounted decompressed size 14 KB',
' dart:_internal/SubListIterable 6 KB',
' @stubs/allocation-stubs/dart:core/ArgumentError 5 KB',
......
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