乐于分享
好东西不私藏

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

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

 提取失败
Android 10+ 限制了 /data/tombstones 直接读取权限
adb root

 获取 root 权限,或改用 adb shell cat /data/tombstones/xxx > local_file 迂回读取
inotifywait: not found
厂商精简了 inotify-tools 工具链
脚本已内置轮询降级逻辑,或手动推送静态二进制:adb push inotifywait /data/local/tmp/
日志文件大小为 0
Tombstone 正在写入中就被拉取
添加延迟等待:sleep 0.5 && adb pull,或监听 close_write 事件而非 create
中文进程名显示乱码
adb 默认编码与设备不一致
执行前设置环境变量:export LC_ALL=C.UTF-8 或 chcp 65001 (Windows)
监控脚本意外退出
设备断开连接导致 adb 管道破裂
外层包裹守护循环: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.shchmod +x 赋予执行权限,连接测试机运行,然后故意制造一个 Native 崩溃(如空指针解引用)。你会看到终端瞬间打印捕获信息,本地目录秒级出现带时间戳的崩溃日志。从此,App 的每一次”临终遗言”都会被你第一时间截获。

点分享

点收藏

点点赞

点推荐

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » App Crash 秒级定位:用 Shell + adb 打造 7*24 小时 Tombstone 监控雷达

评论 抢沙发

6 + 5 =
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
×
订阅图标按钮