// 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:io'; import 'package:flutter_devicelab/framework/devices.dart'; import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; import 'package:flutter_devicelab/framework/utils.dart' as utils; import 'package:flutter_devicelab/tasks/perf_tests.dart' show ListStatistics; import 'package:path/path.dart' as path; const String _bundleName = 'dev.flutter.multipleflutters'; const String _activityName = 'MainActivity'; const int _numberOfIterations = 10; Future<void> _withApkInstall( String apkPath, String bundleName, Function(AndroidDevice) body) async { final DeviceDiscovery devices = DeviceDiscovery(); final AndroidDevice device = await devices.workingDevice as AndroidDevice; await device.unlock(); await device.adb(<String>['install', '-r', apkPath]); try { await body(device); } finally { await device.adb(<String>['uninstall', bundleName]); } } /// Since we don't check the gradle wrapper in with the android host project we /// yank the gradle wrapper from the module (which is added by the Flutter tool). void _copyGradleFromModule(String source, String destination) { print('copying gradle from module $source to $destination'); final String wrapperPath = path.join(source, '.android', 'gradlew'); final String windowsWrapperPath = path.join(source, '.android', 'gradlew.bat'); final String wrapperDestinationPath = path.join(destination, 'gradlew'); final String windowsWrapperDestinationPath = path.join(destination, 'gradlew.bat'); File(wrapperPath).copySync(wrapperDestinationPath); File(windowsWrapperPath).copySync(windowsWrapperDestinationPath); final Directory gradleDestinationDirectory = Directory(path.join(destination, 'gradle', 'wrapper')); if (!gradleDestinationDirectory.existsSync()) { gradleDestinationDirectory.createSync(recursive: true); } final String gradleDestinationPath = path.join(gradleDestinationDirectory.path, 'gradle-wrapper.jar'); final String gradlePath = path.join(source, '.android', 'gradle', 'wrapper', 'gradle-wrapper.jar'); File(gradlePath).copySync(gradleDestinationPath); } Future<TaskResult> _doTest() async { try { final String flutterDirectory = utils.flutterDirectory.path; final String multipleFluttersPath = path.join(flutterDirectory, 'dev', 'benchmarks', 'multiple_flutters'); final String modulePath = path.join(multipleFluttersPath, 'module'); final String androidPath = path.join(multipleFluttersPath, 'android'); final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew'; final String gradlewExecutable = Platform.isWindows ? '.\\$gradlew' : './$gradlew'; final String flutterPath = path.join(flutterDirectory, 'bin', 'flutter'); await utils.eval(flutterPath, <String>['precache', '--android'], workingDirectory: modulePath); await utils.eval(flutterPath, <String>['pub', 'get'], workingDirectory: modulePath); _copyGradleFromModule(modulePath, androidPath); await utils.eval(gradlewExecutable, <String>['assembleRelease'], workingDirectory: androidPath); final String apkPath = path.join(multipleFluttersPath, 'android', 'app', 'build', 'outputs', 'apk', 'release', 'app-release.apk'); TaskResult? result; await _withApkInstall(apkPath, _bundleName, (AndroidDevice device) async { final List<int> totalMemorySamples = <int>[]; for (int i = 0; i < _numberOfIterations; ++i) { await device.adb(<String>[ 'shell', 'am', 'start', '-n', '$_bundleName/$_bundleName.$_activityName' ]); await Future<void>.delayed(const Duration(seconds: 10)); final Map<String, dynamic> memoryStats = await device.getMemoryStats(_bundleName); final int totalMemory = memoryStats['total_kb'] as int; totalMemorySamples.add(totalMemory); await device.stop(_bundleName); } final ListStatistics totalMemoryStatistics = ListStatistics(totalMemorySamples); final Map<String, dynamic> results = <String, dynamic>{ ...totalMemoryStatistics.asMap('totalMemory') }; result = TaskResult.success(results, benchmarkScoreKeys: results.keys.toList()); }); return result ?? TaskResult.failure('no results found'); } catch (ex) { return TaskResult.failure(ex.toString()); } } Future<void> main() async { await task(_doTest); }