App Crash 秒级定位:用 Shell + adb 打造 7*24 小时 Tombstone 监控雷达

App Crash 秒级定位:用 Shell + adb 打造 7×24 小时 Tombstone 监控雷达
你的 App 凌晨 3 点崩溃,用户怒删应用,而你早上 9 点才看到邮件告警?Native 层崩溃像幽灵,复现难、日志散,每次排查都像大海捞针。本文教你用一条 Shell 命令实时监控设备 Tombstone,崩溃发生 3 秒内自动提取日志,让你比用户更早知道问题。
一、原理:给系统装一个”黑匣子记录仪”
想象飞机失事后,调查人员第一时间找黑匣子。Android 的 Tombstone 就是 Native 崩溃的黑匣子——当 C/C++ 层发生段错误(SIGSEGV)或堆栈溢出时,系统会在 /data/tombstones/ 目录生成包含寄存器状态、堆栈跟踪、内存映射的崩溃快照。
但问题是:这些日志躺在设备里,就像黑匣子沉在海底。我们的方案是构建一个监控雷达:用 adb shell 建立持久连接,通过 inotifywait(Linux 文件系统事件监控)实时监听 Tombstone 目录。一旦有新文件诞生,立即通过 adb pull 打捞到本地,实现”崩溃即捕获,秒级响应”。
这相当于在系统崩溃处理流程的末端,插入了一个自动化哨兵,无需修改 App 代码,零侵入实现监控。
二、实战:一条命令链实现全自动监控
以下是可直接运行的完整方案,包含设备监听、日志提取、本地归档和通知推送四大模块。
1. 基础版:单设备实时监控
#!/bin/bash
# crash_monitor.sh - 单设备 Tombstone 实时监控脚本
# 配置区
DEVICE_ID=""# 留空则使用默认设备,多设备时填写具体ID
WATCH_DIR="/data/tombstones"
LOCAL_SAVE="./tombstones_$(date +%Y%m%d)"
POLL_INTERVAL=2 # 轮询间隔(秒),inotify不可用时降级使用
# 创建本地存储目录
mkdir -p "$LOCAL_SAVE"
echo"🚀 启动 Tombstone 监控服务..."
echo"📱 目标设备: ${DEVICE_ID:-默认设备}"
echo"💾 保存路径: $LOCAL_SAVE"
echo"⏱️ 监控模式: 实时事件触发"
# 核心监控逻辑
adb ${DEVICE_ID:+-s $DEVICE_ID} shell "
# 检查并安装 inotify-tools(部分ROM需手动安装)
if ! command -v inotifywait &> /dev/null; then
echo '⚠️ inotifywait 未找到,切换为轮询模式'
while true; do
# 轮询模式:对比文件列表变化
ls -1 $WATCH_DIR > /tmp/tomb_now 2>/dev/null
if [ -f /tmp/tomb_prev ]; then
diff /tmp/tomb_prev /tmp/tomb_now | grep '^>' | while read line; do
filename=\$(echo \$line | awk '{print \$2}')
echo 'NEW_TOMBSTONE:\$filename'
done
fi
cp /tmp/tomb_now /tmp/tomb_prev
sleep $POLL_INTERVAL
done
else
# 事件驱动模式:零延迟捕获
inotifywait -m $WATCH_DIR -e create --format '%f' --exclude 'tombstone_00'
fi
" | whileread filename; do
# 过滤非tombstone文件
[[ "$filename" != tombstone* ]] && continue
TIMESTAMP=$(date'+%H:%M:%S')
echo"[$TIMESTAMP] ⚡ 检测到新崩溃日志: $filename"
# 立即提取到本地,带时间戳重命名防止覆盖
SAFE_NAME="${TIMESTAMP}_${filename}"
if adb ${DEVICE_ID:+-s $DEVICE_ID} pull "$WATCH_DIR/$filename""$LOCAL_SAVE/$SAFE_NAME" 2>/dev/null; then
echo"[$TIMESTAMP] ✅ 提取成功: $SAFE_NAME"
# 可选:提取后立即分析关键信息
echo"[$TIMESTAMP] 🔍 崩溃摘要:"
grep -E 'signal|pid|name|backtrace'"$LOCAL_SAVE/$SAFE_NAME" | head -5
# 可选:推送到企业微信/钉钉(需配置webhook)
# curl -s -X POST "YOUR_WEBHOOK_URL" \
# -H 'Content-Type: application/json' \
# -d "{\"msgtype\":\"text\",\"text\":{\"content\":\"🚨 App崩溃告警\\n文件:$SAFE_NAME\\n时间:$TIMESTAMP\"}}"
else
echo"[$TIMESTAMP] ❌ 提取失败,可能权限不足"
fi
done
逐段解析:
-
• 设备适配:通过 ${DEVICE_ID:+-s $DEVICE_ID}实现单/多设备兼容,未指定时 adb 自动连接唯一设备 -
• 双模式降级:优先使用 inotifywait事件驱动(零 CPU 占用),未安装时自动降级为轮询模式(2秒间隔) -
• 实时管道: adb shell的输出通过管道实时传递给 while 循环,实现流式处理 -
• 原子命名:提取时追加 HH:MM:SS时间戳,避免同一秒内多次崩溃导致文件覆盖 -
• 即时分析:自动 grep 提取 signal 类型、进程名、崩溃堆栈等关键字段,无需人工打开文件
2. 进阶版:多设备并发监控集群
#!/bin/bash
# multi_device_monitor.sh - 多设备并发监控
MONITOR_DIR="./tombstone_cluster_$(date +%Y%m%d)"
mkdir -p "$MONITOR_DIR"
# 获取所有已连接设备列表
mapfile -t DEVICES < <(adb devices | grep -v 'List' | awk '{print $1}' | grep -v '^$')
echo"发现 ${#DEVICES[@]} 台设备,启动并发监控..."
# 为每台设备启动独立监控进程
for device in"${DEVICES[@]}"; do
(
# 每个设备独立目录
DEVICE_DIR="$MONITOR_DIR/$device"
mkdir -p "$DEVICE_DIR"
echo"[$device] 监控启动..."
# 复用单设备逻辑,输出带设备标识
adb -s "$device" shell "
inotifywait -m /data/tombstones -e create --format '%f' 2>/dev/null || \
while true; do ls -1 /data/tombstones; sleep 2; done
" | whileread file; do
[[ "$file" != tombstone* ]] && continue
adb -s "$device" pull "/data/tombstones/$file""$DEVICE_DIR/$(date +%H%M%S)_$file" >/dev/null 2>&1
echo"[$(date '+%H:%M:%S')] [$device] 捕获: $file"
done
) &
done
# 等待所有后台进程
wait
三、坑点:这些报错 90% 的人会踩
|
|
|
|
Permission denied
|
/data/tombstones 直接读取权限 |
adb root
adb shell cat /data/tombstones/xxx > local_file 迂回读取 |
inotifywait: not found |
|
adb push inotifywait /data/local/tmp/ |
|
|
|
sleep 0.5 && adb pull,或监听 close_write 事件而非 create |
|
|
|
export LC_ALL=C.UTF-8 或 chcp 65001 (Windows) |
|
|
|
while true; do ./crash_monitor.sh; sleep 5; done |
四、性能优化:从”能用”到”生产级”
1. 降低监控本身的开销
原始轮询模式(ls + sleep)在 2 秒间隔下,持续产生 adb 命令开销。优化策略:
# 使用持续连接替代反复建立 adb shell
adb shell "
cd /data/tombstones &&
while true; do
# 通过文件修改时间戳检测,比ls更高效
find . -name 'tombstone*' -newer /tmp/.last_check -type f 2>/dev/null
touch /tmp/.last_check
sleep 2
done
"
2. 智能去重与压缩
高频崩溃会产生大量重复 Tombstone,占用磁盘:
# 提取时自动去重(基于文件哈希)
adb shell "cat /data/tombstones/$file" | tee"$LOCAL_SAVE/$file" | md5sum > /tmp/"$file.md5"
# 历史归档:7天前的日志自动压缩
find "$LOCAL_SAVE" -name "tombstone*" -mtime +7 -exec gzip {} \;
3. 生产环境部署建议
-
• systemd 服务化:将脚本注册为系统服务,崩溃自动重启,开机自启 -
• 日志轮转:使用 logrotate管理本地 Tombstone,防止磁盘占满 -
• 分级告警:根据崩溃频率触发不同级别通知(1次/分钟→钉钉,10次/分钟→电话)
现在,将上述脚本保存为 crash_monitor.sh,chmod +x 赋予执行权限,连接测试机运行,然后故意制造一个 Native 崩溃(如空指针解引用)。你会看到终端瞬间打印捕获信息,本地目录秒级出现带时间戳的崩溃日志。从此,App 的每一次”临终遗言”都会被你第一时间截获。







点分享

点收藏

点点赞

点推荐
夜雨聆风
