Steps to reproduce
-
Run on a GitHub Actions macos-15-intel runner
-
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
- Run any integration test:
flutter test integration_test/app_test.dart
- 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
Steps to reproduce
Run on a GitHub Actions
macos-15-intelrunnerBoot an Android emulator (this runner has no hardware GPU, emulator uses SwiftShader):
flutter test integration_test/app_test.dartflutter testnever exits.Works fine on
ubuntu-24.04with KVM.Expected results
flutter testprints the test summary and exits with code 0.Actual results
All tests pass but
flutter testhangs forever. No summary line prints. Process has to be killed externally.Code sample
Code sample
Logs
Logs
During the hang,
psshows a stuck adb child of the dartvm process sitting at 0% CPU. Eitherforce-stoporuninstallcan be the stuck command — both hang on CPU-starved emulators:Killing the stuck adb process unblocks everything:
Consistent across 6+ runs. Killing the stuck adb children fixed it every time.
Where it hangs:
kill()inintegration_test_device.dartruns two adb commands sequentially. Both have no timeout and both can hang:stopApp()inandroid_device.dartcalls_processUtils.stream()— no timeout parameteruninstallApp()inandroid_device.dartcalls_processUtils.run()— no timeout parameterWhy am force-stop and uninstall hang:
On
macos-15-intelthe emulator's qemu uses ~200% CPU for SwiftShader rendering (4-core host).am force-stopcallsActivityManagerService.forceStopPackage()insystem_servervia Binder IPC (AOSP source).uninstallgoes throughPackageManagerServicevia the same Binder mechanism. Whensystem_serveris CPU-starved, Binder calls to it hang.getpropreads from kernel shared memory via__system_property_read_callback()with no IPC (AOSP source). Works fine regardless of CPU pressure.During the hang:
adb devicesworks (host-side adb server, never enters emulator)adb shell getprop sys.boot_completedreturns1(kernel shared memory read)adb shell am force-stophangs (Binder IPC to starvedsystem_server)adb uninstallhangs (Binder IPC to starvedsystem_server)Source locations in Flutter:
stopApp(): android_device.dart — calls_processUtils.stream()with no timeoutuninstallApp(): android_device.dart — calls_processUtils.run()with no timeoutkill(): integration_test_device.dart — awaits both sequentially, no timeoutfinalize(): flutter_platform.dart — no timeout on finalizersPossible fixes:
stopApp()anduninstallApp()that kills the adb process after a few seconds and returns false_processUtils.stream()and_processUtils.run()adb shell killinstead ofam force-stopsince the kernel syscall works even whensystem_serveris starvedOur workaround:
Background watchdog that searches for the two specific adb commands Flutter runs in teardown (
force-stopanduninstall) and kills them:Flutter Doctor output
Doctor output