Skip to content

flutter test hangs after Android integration tests pass on macos-15-intel (stopApp and uninstallApp have no timeout) #187785

Description

@chaudharydeepanshu

Steps to reproduce

  1. Run on a GitHub Actions macos-15-intel runner

  2. Boot an Android emulator (this runner has no hardware GPU, emulator uses SwiftShader):

sdkmanager --install "system-images;android-30;aosp_atd;x86_64"
echo no | avdmanager create avd --force -n test --package "system-images;android-30;aosp_atd;x86_64"
emulator -port 5554 -avd test -no-snapshot-save -no-window -noaudio -no-boot-anim &
adb wait-for-device
# wait until: adb -s emulator-5554 shell getprop sys.boot_completed returns 1
  1. Run any integration test:
flutter test integration_test/app_test.dart
  1. All tests pass. flutter test never exits.

Works fine on ubuntu-24.04 with KVM.

Expected results

flutter test prints the test summary and exits with code 0.

Actual results

All tests pass but flutter test hangs forever. No summary line prints. Process has to be killed externally.

Code sample

Code sample
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();
  testWidgets('simple test', (tester) async {
    expect(1 + 1, 2);
  });
}

Logs

Logs

During the hang, ps shows a stuck adb child of the dartvm process sitting at 0% CPU. Either force-stop or uninstall can be the stuck command — both hang on CPU-starved emulators:

# Run 1 — force-stop hung:
runner  87946 dartvm  0.0  0.0  05:30  adb -s emulator-5554 shell am force-stop com.example.app

# Run 2 — uninstall hung (force-stop was killed by watchdog, uninstall also stuck):
runner  62121 dartvm  0.0  0.0  12:00  adb -s emulator-5554 uninstall com.example.app

Killing the stuck adb process unblocks everything:

$ kill -9 87946
$ kill -9 88799    # uninstall also stuck, kill it too
adb uninstall failed: ProcessException: exit code -9   # this error is normal
🎉 49 tests passed.
# flutter test exits with code 0

Consistent across 6+ runs. Killing the stuck adb children fixed it every time.

Where it hangs:

kill() in integration_test_device.dart runs two adb commands sequentially. Both have no timeout and both can hang:

finalize()
  testDevice.kill()
    device.stopApp(package)        <-- adb shell am force-stop (no timeout)
    device.uninstallApp(package)   <-- adb uninstall (no timeout)
    device.dispose()
    _ddsLauncher.shutdown()
  • stopApp() in android_device.dart calls _processUtils.stream() — no timeout parameter
  • uninstallApp() in android_device.dart calls _processUtils.run() — no timeout parameter

Why am force-stop and uninstall hang:

On macos-15-intel the emulator's qemu uses ~200% CPU for SwiftShader rendering (4-core host).

am force-stop calls ActivityManagerService.forceStopPackage() in system_server via Binder IPC (AOSP source). uninstall goes through PackageManagerService via the same Binder mechanism. When system_server is CPU-starved, Binder calls to it hang.

getprop reads from kernel shared memory via __system_property_read_callback() with no IPC (AOSP source). Works fine regardless of CPU pressure.

During the hang:

  • adb devices works (host-side adb server, never enters emulator)
  • adb shell getprop sys.boot_completed returns 1 (kernel shared memory read)
  • adb shell am force-stop hangs (Binder IPC to starved system_server)
  • adb uninstall hangs (Binder IPC to starved system_server)

Source locations in Flutter:

Possible fixes:

  • Add a timeout to stopApp() and uninstallApp() that kills the adb process after a few seconds and returns false
  • Add a timeout parameter to _processUtils.stream() and _processUtils.run()
  • Use adb shell kill instead of am force-stop since the kernel syscall works even when system_server is starved

Our workaround:

Background watchdog that searches for the two specific adb commands Flutter runs in teardown (force-stop and uninstall) and kills them:

flutter test integration_test/app_test.dart &
CMD_PID=$!

(
  while kill -0 $CMD_PID 2>/dev/null; do
    sleep 30
    for pattern in force-stop uninstall; do
      for pid in $(pgrep -f "$pattern"); do
        PCMD=$(ps -p "$pid" -o args=)
        echo "$PCMD" | grep -q adb || continue
        echo "Killing stuck adb $pattern (PID $pid)"
        kill -9 "$pid"
      done
    done
  done
) &

wait $CMD_PID

Flutter Doctor output

Doctor output
Flutter 3.44.1 • channel stable
Framework • revision 924134a44c
Engine • revision c416acfeb8
Tools • Dart 3.12.1 • DevTools 2.57.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    a: tests"flutter test", flutter_test, or one of our testsfyi-toolFor the attention of Flutter Tool teamplatform-androidAndroid applications specificallyteam-androidOwned by Android platform team

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions