v0.9.4: a turn keeps running when the app is not on screen

A phone freezes an app it cannot see, and the front end had nothing holding
it: a turn that took minutes -- a long shell command, a provider that thinks,
a build -- stopped quietly the moment the user pressed home, and the answer
was only there if the window happened to come back. The engine's own /attach
flow made this visible: an APK turn survived, a pocket did not.

- app/android/src/xyz/whcself/cstagent/CstService.java: a foreground service
  started with an explicit component (nothing outside the app can reach it,
  no intent filter) for as long as a turn runs. Being a foreground service
  makes the process one Android neither freezes nor kills; a partial wake
  lock (30 min ceiling) keeps the CPU awake with the screen off. Its ongoing
  notification says what is running -- "CST-agent is working" plus the first
  line of the prompt -- on the same cst-agent channel the notification_send
  tool uses, and taps back into the app. A phone that refuses the foreground
  start (Android 12+ does, from the background) loses the protection, not the
  turn: the failure is caught and the service stops itself.
- Manifest: FOREGROUND_SERVICE, FOREGROUND_SERVICE_DATA_SYNC (API 34+ wants
  the typed one) and WAKE_LOCK, plus the <service> with
  foregroundServiceType="dataSync". The first build of this failed with
  "Expected '>', but got ' '" -- a manifest comment cannot contain "--".
- Front end: app::holdForeground(text) / app::releaseForeground() in
  ToolProvider.h, one call for every platform -- Android starts and stops the
  service through JNI, a desktop has nothing to hold (its window is the app).
  AgentCore::send() calls it when the turn starts (firstLine() of the prompt
  is what the notification says) and finishTurn() releases it, so the
  notification exists exactly as long as the work does. CST_APP_NO_SERVICE=1
  keeps a test run from touching the phone.
- On the NX789J, with the app sent home and the screen off: the service read
  back isForeground=true with its notification, the wake lock cst-agent:turn
  was taken at the start of the turn and dropped at its end, run_shell
  "sleep 60" finished with the screen dark, and the service was gone after.

Desktop: build clean, --uitest all green, --selftest and cst-app-selftest OK
(the hold is a no-op there, so nothing about the Qt side changed).

Version 0.9.4.
This commit is contained in:
WHC
2026-10-11 16:51:39 +08:00
parent d4f65b17cf
commit 7299f39245
9 changed files with 304 additions and 5 deletions
+6
View File
@@ -374,6 +374,10 @@ androiddeployqt copies `app/android/` with the rest of the package source and
Qt's Gradle template puts its `src/` on `java.srcDirs`, so no build-script
change is needed (`Notifier.java` is the first one; a Java helper is the only
way to catch a throwable where the platform throws instead of returning).
`CstService.java` (the foreground service that holds a phone awake while a
turn runs) went in the same way; it is started by `app::holdForeground()`
when a turn begins and stopped by `app::releaseForeground()` when it ends,
so nothing about it is visible when the app is idle.
## Status
@@ -398,6 +402,8 @@ way to catch a throwable where the platform throws instead of returning).
transcript draws a file card with Open and Share (see the Files section)
- [x] Android platform tools (JNI: notification, clipboard, share sheet) and the
file card's open/share through the app's FileProvider
- [x] a turn keeps running with the app off screen (Android foreground service
+ wake lock; nothing to do on a desktop)
- [ ] a real turn driven through the window (needs a provider key)
- [ ] SAF file picker, the back gesture, the icon glyphs on the phone
- [ ] Kirigami (the rest of the Breeze look: colors, controls), tray,