Skip to content

Commit

Permalink
Add Android lifecycles test (#99319)
Browse files Browse the repository at this point in the history
  • Loading branch information
Emmanuel Garcia authored Mar 1, 2022
1 parent 64d9ea6 commit 6c818d7
Show file tree
Hide file tree
Showing 6 changed files with 289 additions and 57 deletions.
11 changes: 11 additions & 0 deletions .ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2388,6 +2388,17 @@ targets:
task_name: android_choreographer_do_frame_test
scheduler: luci

- name: Linux_android android_lifecycles_test
bringup: true
recipe: devicelab/devicelab_drone
presubmit: false
timeout: 60
properties:
tags: >
["devicelab","android","linux"]
task_name: android_lifecycles_test
scheduler: luci

- name: Mac build_aar_module_test
recipe: devicelab/devicelab_drone
timeout: 60
Expand Down
3 changes: 2 additions & 1 deletion TESTOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@

## Linux Android DeviceLab tests
/dev/devicelab/bin/tasks/analyzer_benchmark.dart @zanderso @flutter/tool
/dev/devicelab/bin/tasks/android_choreographer_do_frame_test.dart @blasten @flutter/engine
/dev/devicelab/bin/tasks/android_defines_test.dart @zanderso @flutter/tool
/dev/devicelab/bin/tasks/android_lifecycles_test.dart @blasten @flutter/engine
/dev/devicelab/bin/tasks/android_obfuscate_test.dart @zanderso @flutter/tool
/dev/devicelab/bin/tasks/android_picture_cache_complexity_scoring_perf__timeline_summary.dart @flar @flutter/engine
/dev/devicelab/bin/tasks/android_stack_size_test.dart @zanderso @flutter/tool
Expand Down Expand Up @@ -71,7 +73,6 @@
/dev/devicelab/bin/tasks/opacity_peephole_fade_transition_text_perf__e2e_summary.dart @flar @flutter/engine
/dev/devicelab/bin/tasks/opacity_peephole_col_of_alpha_savelayer_rows_perf__e2e_summary.dart @flar @flutter/engine
/dev/devicelab/bin/tasks/opacity_peephole_grid_of_alpha_savelayers_perf__e2e_summary.dart @flar @flutter/engine
/dev/devicelab/bin/tasks/android_choreographer_do_frame_test.dart @blasten @flutter/engine

## Windows Android DeviceLab tests
/dev/devicelab/bin/tasks/basic_material_app_win__compile.dart @zanderso @flutter/tool
Expand Down
10 changes: 10 additions & 0 deletions dev/devicelab/bin/tasks/android_lifecycles_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// 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:flutter_devicelab/framework/framework.dart';
import 'package:flutter_devicelab/tasks/android_lifecycles_test.dart';

Future<void> main() async {
await task(androidLifecyclesTest());
}
4 changes: 2 additions & 2 deletions dev/devicelab/lib/framework/devices.dart
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ class AndroidDevice extends Device {
}
}

/// Executes [command] on `adb shell` and returns its exit code.
/// Executes [command] on `adb shell`.
Future<void> shellExec(String command, List<String> arguments, { Map<String, String>? environment, bool silent = false }) async {
await adb(<String>['shell', command, ...arguments], environment: environment, silent: silent);
}
Expand Down Expand Up @@ -637,7 +637,7 @@ class AndroidDevice extends Device {
late final StreamController<String> stream;
stream = StreamController<String>(
onListen: () async {
await adb(<String>['logcat', '--clear']);
await adb(<String>['logcat', '-c']);
final Process process = await startProcess(
adbPath,
// Make logcat less chatty by filtering down to just ActivityManager
Expand Down
106 changes: 52 additions & 54 deletions dev/devicelab/lib/tasks/android_choreographer_do_frame_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@ const List<String> kSentinelStr = <String>[
'==== sentinel #3 ====',
];

// Regression test for https://github.com/flutter/flutter/issues/98973
// This test ensures that Choreographer#doFrame finishes during application startup.
// This test fails if the application hangs during this period.
// https://ui.perfetto.dev/#!/?s=da6628c3a92456ae8fa3f345d0186e781da77e90fc8a64d073e9fee11d1e65
/// Tests that Choreographer#doFrame finishes during application startup.
/// This test fails if the application hangs during this period.
/// https://ui.perfetto.dev/#!/?s=da6628c3a92456ae8fa3f345d0186e781da77e90fc8a64d073e9fee11d1e65
/// Regression test for https://github.com/flutter/flutter/issues/98973
TaskFunction androidChoreographerDoFrameTest({
String? deviceIdOverride,
Map<String, String>? environment,
}) {
final Directory tempDir = Directory.systemTemp
Expand Down Expand Up @@ -87,18 +86,19 @@ Future<void> main() async {
}

section('Flutter run (mode: $mode)');
late Process run;
await inDirectory(path.join(tempDir.path, 'app'), () async {
final Process run = await startProcess(
run = await startProcess(
path.join(flutterDirectory.path, 'bin', 'flutter'),
flutterCommandArgs('run', <String>['--$mode', '--verbose']),
);
});

int currSentinelIdx = 0;
final StreamSubscription<void> stdout = run.stdout
.transform<String>(utf8.decoder)
.transform<String>(const LineSplitter())
.listen((String line) {

int currSentinelIdx = 0;
final StreamSubscription<void> stdout = run.stdout
.transform<String>(utf8.decoder)
.transform<String>(const LineSplitter())
.listen((String line) {
if (currSentinelIdx < sentinelCompleters.keys.length &&
line.contains(sentinelCompleters.keys.elementAt(currSentinelIdx))) {
sentinelCompleters.values.elementAt(currSentinelIdx).complete();
Expand All @@ -107,61 +107,59 @@ Future<void> main() async {
} else {
print('stdout: $line');
}

});

final StreamSubscription<void> stderr = run.stderr
.transform<String>(utf8.decoder)
.transform<String>(const LineSplitter())
.listen((String line) {
print('stderr: $line');
});

final Completer<void> exitCompleter = Completer<void>();

unawaited(run.exitCode.then((int exitCode) {
exitCompleter.complete();
}));
final StreamSubscription<void> stderr = run.stderr
.transform<String>(utf8.decoder)
.transform<String>(const LineSplitter())
.listen((String line) {
print('stderr: $line');
});

section('Wait for sentinels (mode: $mode)');
for (final Completer<void> completer in sentinelCompleters.values) {
if (nextCompleterIdx == 0) {
// Don't time out because we don't know how long it would take to get the first log.
final Completer<void> exitCompleter = Completer<void>();

unawaited(run.exitCode.then((int exitCode) {
exitCompleter.complete();
}));

section('Wait for sentinels (mode: $mode)');
for (final Completer<void> completer in sentinelCompleters.values) {
if (nextCompleterIdx == 0) {
// Don't time out because we don't know how long it would take to get the first log.
await Future.any<dynamic>(
<Future<dynamic>>[
completer.future,
exitCompleter.future,
],
);
} else {
try {
// Time out since this should not take 1s after the first log was received.
await Future.any<dynamic>(
<Future<dynamic>>[
completer.future,
completer.future.timeout(const Duration(seconds: 1)),
exitCompleter.future,
],
);
} else {
try {
// Time out since this should not take 1s after the first log was received.
await Future.any<dynamic>(
<Future<dynamic>>[
completer.future.timeout(const Duration(seconds: 1)),
exitCompleter.future,
],
);
} on TimeoutException {
break;
}
}
if (exitCompleter.isCompleted) {
// The process exited.
} on TimeoutException {
break;
}
nextCompleterIdx++;
}
if (exitCompleter.isCompleted) {
// The process exited.
break;
}
nextCompleterIdx++;
}

section('Quit app (mode: $mode)');
run.stdin.write('q');
await exitCompleter.future;
section('Quit app (mode: $mode)');
run.stdin.write('q');
await exitCompleter.future;

section('Stop listening to stdout and stderr (mode: $mode)');
await stdout.cancel();
await stderr.cancel();
run.kill();
});
section('Stop listening to stdout and stderr (mode: $mode)');
await stdout.cancel();
await stderr.cancel();
run.kill();

if (nextCompleterIdx == sentinelCompleters.values.length) {
return TaskResult.success(null);
Expand Down
Loading

0 comments on commit 6c818d7

Please sign in to comment.