Skip to content

Agent brief: app not staying foreground (AutoMobile CI)

Audience: IDE agents and app engineers debugging host app behavior when AutoMobile JUnit tests report odd failures in CI or locally.

Symptoms (often together):

  • launchApp returns success, but the launcher (e.g. Nexus Launcher) stays focused.
  • daemon.log shows the foreground package as com.google.android.apps.nexuslauncher (or another launcher), not your applicationId.
  • observe can still pass while the wrong screen is visible (valid snapshot ≠ your app’s UI).
  • Later steps (tapOn, waitFor) fail because elements exist only in your app.
  • failedStep.failureObservation in the plan result shows launcher packageName at failure time.

Goal: Decide whether the problem is your APK / activity lifecycle (crash, immediate finish, wrong component) vs test plan assertions that allow the launcher. Collect evidence the app team can act on.


What a narrow CI logcat already proves

Some pipelines only archive logcat filtered to activity / task lines (e.g. ActivityTaskManager). That is enough to see intents and transitions, and often enough to see CtrlProxy working.

It is usually not enough to answer: why did my process disappear or never hold focus?

If the saved logcat has no lines like:

  • FATAL EXCEPTION
  • AndroidRuntime
  • Process … has died
  • SecurityException / IllegalStateException tied to your package

…then you are not missing a hidden line inside that same file. You need wider logcat or dumpsys captured in the same time window as the failure (or reproduce locally with the same APK).


Evidence to collect (priority order)

New vs old file: adb logcat -c clears the device’s ring buffer, then you launch and adb logcat -d dumps a fresh capture from that session. That does not modify or append to an existing CI logcat artifact—you are generating new text to save or paste. For the same APK behavior as CI, use the same build (flavor, signing, env) and the same emulator/API level when possible.

Beyond logcat: steps 1–3 are pidof / dumpsys (not logcat). Keep them in the same bundle you share—they often explain focus/stack when logcat is still noisy.

If correlating with a CI failure: still attach daemon.log (or the CI line that points to it) and JUnit / Gradle failure output so the timeline matches; the adb block above is for device-side root cause.

Use the same application id your YAML plan uses (appId). Replace PACKAGE below (e.g. com.example.app).

1. Process still alive after launch

bash adb wait-for-device adb shell pidof PACKAGE

  • Empty output: process is not running (crash, immediate finish(), or never started correctly).

2. What window actually has focus

bash adb shell dumpsys window | grep -E 'mCurrentFocus|mFocusedApp'

  • If the line shows a launcher package instead of PACKAGE, your app is not the focused window—even if am start / launchApp appeared to succeed.

3. Activity stack (optional but high signal)

bash adb shell dumpsys activity activities | head -n 200

Search the output for PACKAGE and the top Resumed / mResumedActivity section. This shows whether your activity resumed and what sits above it in the stack.

4. Broader logcat (this is the main gap vs narrow CI captures)

Clear, launch once, then dump errors:

bash adb logcat -c adb shell monkey -p PACKAGE -c android.intent.category.LAUNCHER 1 sleep 3 adb logcat -d '*:E' 'AndroidRuntime:E' 'ActivityManager:I' 'WindowManager:I' | tail -n 200

If your package has a known log tag, also run (replace YourTag):

bash adb logcat -d | grep -E 'AndroidRuntime|FATAL|PACKAGE|YourTag' | tail -n 120

Look for: the first stack trace or fatal error mentioning your package after launch.

5. PID-scoped logcat (when the process exists briefly)

Right after launch, try:

bash PID=$(adb shell pidof PACKAGE | tr -d '\r') test -n "$PID" && adb logcat --pid="$PID" -d | tail -n 150

If pidof is empty, skip this and rely on step 4 (wide logcat).


After a fresh run: what you are looking for

There is no single canonical filename CI must produce. What matters is that you saved plain text for each command (upload as job artifacts, or paste into a ticket). Treat that bundle as one “evidence package.”

1. pidof output (step 1)
- Good for debugging: a numeric PID (process still alive a moment after launch).
- Smoking gun: empty → app is not running; pair with logcat for crash vs silent exit.

2. mCurrentFocus / mFocusedApp lines (step 2)
- Good: your PACKAGE appears on the focus line.
- Problem: launcher or another package → explains why AutoMobile still “sees” launcher UI even after launchApp.

3. Wide logcat (step 4, and step 5 if you had a PID)
Scan top-to-bottom for the first occurrence of any of:

  • FATAL EXCEPTION (especially with your package or AndroidRuntime below it)
  • AndroidRuntime: E stack traces
  • Process <your.package> has died (wording varies by API)
  • SecurityException, IllegalArgumentException, IllegalStateException mentioning your code

That block (a few dozen lines around the first hit) is usually the artifact you hand to the app team.

4. dumpsys activity excerpt (step 3)
Use when logcat is clean but focus is wrong: find mResumedActivity / Resumed and whether your ActivityRecord appears, finished, or sits under a dialog/overlay.

5. Still running AutoMobile tests
Keep daemon.log + JUnit/Gradle failure snippet from the same run so you know which plan step failed and what the daemon thought the foreground app was.

Bottom line: you are looking for actionable text: either a crash stack in logcat, or focus/stack proof that your activity never resumed or exited immediately—saved as files or logs you can link, not a specific proprietary “artifact type.”


How this maps to fixes

Finding Likely area
FATAL EXCEPTION / AndroidRuntime for your package App bug (startup crash, missing dep, migration, etc.)
SecurityException / permission denial Manifest, runtime permissions, or device policy
pidof empty, no crash in logcat Immediate finish(), wrong launcher activity, or process name / user profile mismatch
Focus stays on launcher, app process alive Overlay, dialog, or another activity on top—investigate stack (step 3)
Focus wrong, tests still “observe” Harden the YAML (next section)

Harden AutoMobile YAML (parallel track)

Treat launchApp success as start was attempted, not your UI is visible.

Immediately after launchApp, wait for something only your app can show (resource id including your package):

```yaml - tool: launchApp appId: PACKAGE label: Start app

  • tool: observe label: Wait for app-specific chrome waitFor: elementId: “PACKAGE:id/your_main_view” timeout: 15000 ```

waitFor must include text or elementId (not timeout alone). See Writing Tests → observe.


Full AutoMobile / CI context

When sharing with an agent, attach: CI job excerpt, daemon.log, JUnit failure, and the artifacts from steps 1–4 above (plus step 5 when pidof returns a PID) from the same failing run or a local repro with the same APK.