4 服务状态排查:dumpsys activity services
后台服务是 Android 多任务与跨进程通信的核心载体。服务异常会导致应用功能丢失、界面无法刷新、NFC/WiFi 扫描失效等现象。本章从 dumpsys activity services 输出入手,建立服务存活、绑定关系与异常停止的排查路径。
现象识别
用户或测试报告:
· 应用后台运行一段时间后,蓝牙/定位/通知栏功能突然不可用。
· 使用
· 客户端 Binder 调用返回
用户或测试报告:
· 应用后台运行一段时间后,蓝牙/定位/通知栏功能突然不可用。
· 使用
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 或不存在 | 服务未关联进程(未启动或已停止) |
appDied | false | true | 进程死亡,需查明崩溃或杀进程原因 |
killed | false | true | 被 AMS 主动杀死(低内存、ANR、权限) |
crashCount | 0 | >0 | 服务异常退出次数,结合 lastCrashTime 判断频率 |
crashReason | null | 有描述 | 崩溃原因字符串(如 NullPointerException) |
Restarting | false | true | 系统正在重启服务(可能发生死循环重启) |
clientCount | >0 | 0 | 无绑定客户端但服务仍运行(可能泄漏或非绑定启动) |
4.2 原因定位:故障树 + 判断规则
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 启动受
从 Android 12+ 开始,foreground service 启动受
foregroundServiceType 声明强制约束,缺少适配会导致 ForegroundServiceTypeNotAllowedException。务必在 Manifest 中正确配置:
<service
android:name=".MyService"
android:foregroundServiceType="location|mediaPlayback"
android:exported="false" />