4 服务状态排查:dumpsys activity services

后台服务是 Android 多任务与跨进程通信的核心载体。服务异常会导致应用功能丢失、界面无法刷新、NFC/WiFi 扫描失效等现象。本章从 dumpsys activity services 输出入手,建立服务存活、绑定关系与异常停止的排查路径。

现象识别
用户或测试报告:
· 应用后台运行一段时间后,蓝牙/定位/通知栏功能突然不可用。
· 使用 adb shell dumpsys activity services | grep -A 10 "服务名" 发现服务状态为 null 或 stopping。
· 客户端 Binder 调用返回 DeadObjectException。

4.1 数据采集:dumpsys activity services

采集完整快照,聚焦关键字段:

adb shell dumpsys activity services [package_name] 2>&1 | head -n 200

输出示例(已脱敏):

ServiceRecord{3a1b2c3d u0 com.example.myapp/.MyService}
  IntentFilter: null
  Bindings:
    * Intent{act=com.example.ACTION_BIND}:
      ConnectionRecord{4e5f6a7b u0 null}
        conn: android.os.BinderProxy@1234567
        flags: BIND_AUTO_CREATE
        client: ProcessRecord{8a9b0c1d u0:com.example.client/1234}
  AppIntent: Intent{act=com.example.action.START}
  Created: 2025-03-15 14:30:22
  Starting: 2025-03-15 14:30:22
  LastActivity: 2025-03-15 14:32:10
  Restarting: false
  CreatedProcess: pid 12345
  Process: ProcessRecord{8a9b0c1d u0:com.example.myapp/12345}
  Crash Count: 2
  crashReason: null
  lastCrashTime: 2025-03-15 14:31:05
  isForeground: false
  foregroundId: -1
  visible: true
  clientCount: 1
  pendingStarts: 0
  bindings: 1
  killed: false
  appPid: 12345
  appDied: false

关键字段排查表

字段正常状态异常标志排查意义
appPid正数-1 或不存在服务未关联进程(未启动或已停止)
appDiedfalsetrue进程死亡,需查明崩溃或杀进程原因
killedfalsetrue被 AMS 主动杀死(低内存、ANR、权限)
crashCount0>0服务异常退出次数,结合 lastCrashTime 判断频率
crashReasonnull有描述崩溃原因字符串(如 NullPointerException)
Restartingfalsetrue系统正在重启服务(可能发生死循环重启)
clientCount>00无绑定客户端但服务仍运行(可能泄漏或非绑定启动)

4.2 原因定位:故障树 + 判断规则

服务状态排查故障树 服务异常故障树 服务不可用 服务未存活 存在但绑定异常 appPid ≡ -1 appDied ≡ true clientCount=0 bindings=0 crashCount>0 killed ≡ true ANR / Force Stop 查看 logcat LowMemoryKiller / OOM dmesg / event log 排查提示 结合 logcat -b events | grep am_crash 及 logcat -b main | grep ServiceManager

4.3 修复动作

根据故障树分支采取对应措施:

诊断结果修复动作
appPid == -1 且 appDied == false服务没有启动。检查是否调用了 startService() 或 bindService();查看调用链是否受 BOOT_COMPLETED 限制或权限不足。
appDied == true进程已死亡。检查 logcat 中 am_proc_died 及 am_crash 事件。修复崩溃代码或增加 try-catch;若被 LMK 杀死,评估内存占用并降低后台 Service 优先级。
killed == true被系统主动杀死。查看 am_kill_all 或 am_anr 日志。若是 ANR,优化 Service onBind / onStartCommand 执行时间;若是后台限制,改用 foreground service + 通知。
clientCount == 0 且 bindings == 0无客户端绑定但服务仍在运行。确认是否存在非绑定启动的服务泄漏,检查 stopSelf() 调用时机,或使用 stopService() 主动终止。
crashCount > 0服务反复崩溃。提取 crashReason 字段,配合 logcat -b crash 定位具体异常,修复后建议增加服务重启保护(如重启次数上限)。

4.4 复测

执行修复后,再次运行数据采集命令,确认以下状态恢复:

adb shell dumpsys activity services | grep -E "(appPid|appDied|killed|crashCount|Restarting)"

期望输出:

appPid: 24567
appDied: false
killed: false
crashCount: 0
Restarting: false

同时从客户端侧验证服务可用性:

# 客户端场景:向服务发送 binder 调用并检查返回
adb shell am start -n com.example.client/.MainActivity
# 检查服务是否响应预期功能
复测小技巧
使用 adb shell dumpsys activity services | grep -c "appDied=true" 快速判断进程中是否存在死亡标记。
若修复后仍有死亡现象,可在 service 的 onDestroy() 中添加日志,确认是被系统回收还是因异常退出。

4.5 预防机制

长期稳定运行的后台服务应遵循以下规则:

策略实现方式
禁止长时间主线程阻塞使用 HandlerThread 或 IntentService 处理耗时工作,避免 ANR。
使用前台服务高危服务(定位、播放)必须在 onStartCommand 后立即调用 startForeground() 并给予通知。
绑定保护onBind() 返回 IBinder 后,确保 Binder 对象线程安全;客户端在 onServiceDisconnected 中处理重连。
异常兜底在 onStartCommand 返回 START_STICKY 或 START_REDELIVER_INTENT 让系统自动重启服务;但需结合 crashCount 限制反复重启。
内存监控在 onLowMemory() 或 onTrimMemory() 中释放可丢弃资源,降低被杀概率。
注意
从 Android 12+ 开始,foreground service 启动受 foregroundServiceType 声明强制约束,缺少适配会导致 ForegroundServiceTypeNotAllowedException。务必在 Manifest 中正确配置:
<service
    android:name=".MyService"
    android:foregroundServiceType="location|mediaPlayback"
    android:exported="false" />