Android日志能力之持久化转储及回传的闭环方案(下)

Android日志能力之持久化转储及回传的闭环方案(下)

上帝反馈后

在碰到一些奇奇怪怪的系统问题时,如视频无法播放、网络异常、触摸无响应等等疑难杂症单单靠应用级别的异常信息怕是不能正常分析的,如果没有相应的日志获取能力,那面对用户的应该就是一块板砖,而面对我们的可能就是来自上帝的批判,因此如何在上帝反馈问题后第一时间能够获取到有用的信息并给予用户正向的反馈是及其重要的。

因此,在系统层面设计了一种持久化转储日志信息的三把刀方案:logdump、kdump、xdump。

logdump

logdump最初的设计初衷是为了持久化存储Android log,能够在用户机器出现问题时提供给研发端更多的信息便于分析定位。起初在设计时V1.0版本时只能保存最大两次开机后的日志信息,并且没有增加时间戳区别,回传的日志文件比较不清晰,在进行二次重构时,充分考虑了时间因素,增加了时间戳,能更明显的辨别日志记录的起始位置,由于持久化记录日志会对emmc有损耗,因此,结合公司的物联服务做了下发开关的操作,使得能够进行按需操作:

#!/system/bin/sh

LOG_PATH="/data/logdump"
LOG_DIR_MAX_COUNT=5

if [ ! -d "$LOG_PATH" ]; then
    mkdir -p $LOG_PATH
fi

# remove files not in correct directory.
REMOVE_FILES=`ls -F $LOG_PATH | grep -v /$`
for r_file in $REMOVE_FILES
do
    rm -f $LOG_PATH/$r_file
done

CUR_LOG_DIR_COUNT=`ls -F $LOG_PATH | grep /$ | wc -l`

if [ "$CUR_LOG_DIR_COUNT" -ge "$LOG_DIR_MAX_COUNT" ]; then
    REMOVE_DIR_COUNT=`expr $CUR_LOG_DIR_COUNT - $LOG_DIR_MAX_COUNT + 1`
    REMOVE_DIRS=`ls -F $LOG_PATH | grep /$ | head -$REMOVE_DIR_COUNT`
    for r_dir in $REMOVE_DIRS
    do
        rm -rf $LOG_PATH/$r_dir
    done
fi

if [ "$CUR_LOG_DIR_COUNT" -gt "0" ]; then
    COPY_DIR=`ls -F $LOG_PATH | grep /$ | tail -1`
    cp -rf /sys/fs/pstore/ $LOG_PATH/$COPY_DIR
fi

CUR_LOG_DIR_WITH_TIMESTAMP=`date +%Y-%m-%d_%H%M%S`
mkdir -p $LOG_PATH/$CUR_LOG_DIR_WITH_TIMESTAMP

logcat -G 16m
logcat -v threadtime -r8192 -n6 -f $LOG_PATH/$CUR_LOG_DIR_WITH_TIMESTAMP/log.txt &

在boot阶段logcat的服务已经启动并开始记录日志,因此在init.rc配置中增加了如下属性检测,当检测到persist.sys.logdump=true时则启动logdump的service。

service logdump /system/bin/logdump
    class main
    user root
    group root lodump system
    seclabel u:r:logdump:s0
    oneshot

on boot && property:persist.sys.logdump=true
    start logdump

而persist.sys.logdump的开关控制则由物联平台进行管理下发,实现了远程按需配置的功能。

kdump

通常在userdebug中获取kernel的日志时都是通过dmesg获取,但是dmesg仅仅只能将目前内核日志缓冲区打印出来,而内核日志缓冲区大小是有限的,往往我们在发现问题时再去获取内核日志时打印的dmesg已经不是现场了,对与内核相关问题的调试成为业务很大痛点。并且userdebug我们还能使用adb进行打印,但是出货的user版本我们根本无法获取现场的内核信息,若出现内核相关问题,只能换机调回来调式,因此非常有必要集成一个持续获取内核日志的工具服务。

采用从init起一个服务的方法,专门用于往/data/kdump/中记录kernel log,最大保存5次开机以来的kernel log,每次存储的日志元数据单文件最大支持20M,采用gzip流压缩方式,将占用空间大小尽可能缩减,避免更多的EMMC占用,采用shell编写了一个覆盖算法将新日志保存,实现旧日志清除。

#!/system/bin/sh

LOG_ROOT_DIR="/data/kdump"
KMSG_DIR_MAX_COUNT=5
KMSG_FILE_MAX_COUNT=10

# Create kmsg root directory if not exist.
if [ ! -f "$LOG_ROOT_DIR" ]; then
    mkdir -p $LOG_ROOT_DIR
fi

# Remove files which're not in correct directory.
REMOVE_FILES=`ls -F $LOG_ROOT_DIR | grep -v /$`
for r_file in $REMOVE_FILES
do
    rm -f $LOG_ROOT_DIR/$r_file
done

# Remove more than $KMSG_DIR_MAX_COUNT kmsg storage directories.
CUR_LOG_DIR_COUNT=`ls -F $LOG_ROOT_DIR | grep /$ | wc -l`

if [ "$CUR_LOG_DIR_COUNT" -ge "$KMSG_DIR_MAX_COUNT" ]; then
    REMOVE_DIR_COUNT=`expr $CUR_LOG_DIR_COUNT - $KMSG_DIR_MAX_COUNT + 1`
    REMOVE_DIRS=`ls -F $LOG_ROOT_DIR | grep /$ | head -$REMOVE_DIR_COUNT`
    for r_dir in $REMOVE_DIRS
    do
        rm -rf $LOG_ROOT_DIR/$r_dir
    done
fi

# Create new kmsg storage directory with named timestamp.
CUR_LOG_DIR_WITH_TIMESTAMP=`date +%Y-%m-%d_%H%M%S`
mkdir -p $LOG_ROOT_DIR/$CUR_LOG_DIR_WITH_TIMESTAMP
echo "Create $LOG_ROOT_DIR/$CUR_LOG_DIR_WITH_TIMESTAMP"

do_kmsg_dump(){
   
    while :
    do
        for i in $(seq 1 $KMSG_FILE_MAX_COUNT)
        do
            f_index=$(expr $KMSG_FILE_MAX_COUNT - $i)
            # Move new kmsg to overlay old.
            if [ -f "$LOG_ROOT_DIR/$CUR_LOG_DIR_WITH_TIMESTAMP/kernel_msg_$(expr $f_index - 1)".gz ]; then
                mv $LOG_ROOT_DIR/$CUR_LOG_DIR_WITH_TIMESTAMP/kernel_msg_$(expr $f_index - 1).gz \
                    $LOG_ROOT_DIR/$CUR_LOG_DIR_WITH_TIMESTAMP/kernel_msg_$f_index.gz -f
            fi
        done
        # Save up to 40MB kmsg metadata in every dump file, use gzip to compress it.
        dd if=/proc/kmsg bs=1k count=40960 | gzip > $LOG_ROOT_DIR/$CUR_LOG_DIR_WITH_TIMESTAMP/kernel_msg_0.gz
    done
}

do_kmsg_dump

在设置单文件元数据大小时发现dd的流采集大小设置为20M时实际最多采集8MB大小原始kmsg,因此调整数据流大小最大40MB,压缩后的gzip包最大不超过2MB,日志目录保存最大10个文件,单目录最大20MBEMMC损耗,全系统最大20*5=100MBEMMC空间损耗,对用户来说整体空间损耗可忽略不计。

xdump

前两个dump功能是日志转储的话,xdump则是进行日志收集功能,将所有的有用信息进行可选择性的收集及上报操作。

在设计时采用了getopt进行参数解析,使得容错性更强,采用主从分离架构,使得单个脚本能够单独使用,由xdump作为总执行脚本放在/system/xbin/xdump下,其余脚本放在/system/etc/xdumps/script下,分别有:android_base_dump、data_data_dump、kernel_base_dump、android_apk_dump:

在这里插入图片描述

xdump v2.00 (2021-08-31) log catcher tool.

usage: xdump [COMMAND] [ARGS]

     -a: dump all logs
     -b [args]: dump android base logs
          all : dump all android base log
          system : dump system core info message.
          media : dump media [video|aduio] info.
          net : dump network info.
          graphic : dump graphic [activity|screen|window] info.
          log : dump system log [anr|dropbox|logdump] info.
     -d [args|<package name>]: dump /data/data packages files.
          all : dump all packages data files
          thirdpart : dump all thirdpart packages data files
          company : dump all company packages data files
          <package name> : dump specific packages data files,
                           each package split with ':'.
     -k: dump kernel base logs
     -s [all|<package name>]: dump company apk xlog files.
          all : dump all packages data files
          <package name> : dump specific packages data files,
                           each package split with ':'.
     -P <path>: dump files path.
     -z : pack xdump files with gzip.
     -h: show this message.
#!/bin/sh

############################################
# @Description: xdump log tool
# @Version: V2.0 2021-08-31
############################################

DEFAULT_XDUMP_ROOT_PATH=/sdcard
xdump_log_root_path=$DEFAULT_XDUMP_ROOT_PATH

XDUMP_SCRIPT_PATH=/system/etc/xdumps/script
XDUMP_LOG_ROOT_NAME=$(getprop ro.serialno)
XDUMP_PACK_FILE_NAME=`date +%Y-%m-%d_%H%M%S`

......

#Help
do_help()
{
   
    ......
}

do_start()
{
   
    echo "------------------start xdump------------------"
    start_time=$(date +%s)
}

do_finish()
{
   
    end_time=$(date +%s)
    delta_time=$(expr ${
    end_time} - ${
    start_time})
    echo "-----finish xdump. spend: ${delta_time} s------"
    if [ $XDUMP_PACK_FLAG -eq 1 ]; then
        echo "Log file path: $xdump_file_path/${XDUMP_PACK_FILE_NAME}.tgz"
    else
        echo "Log file path: $xdump_file_path/${XDUMP_LOG_ROOT_NAME}"
    fi
}

create_xdump_log_dir()
{
   
    xdump_file_path=$xdump_log_root_path/xdumps
    echo "create xdump log dir: $xdump_file_path"
    create_dir_success=`mkdir -p $xdump_file_path 2>&1 > /dev/null ; echo $?`
    if [ $create_dir_success -ne 0 ]; then
        echo "Failed to create $xdump_file_path, please check path."
        exit 1
    fi
}

parse_android_base_params()
{
   
......
}

parse_data_data_params()
{
   
......
}

parse_android_apk_params()
{
   
......
}

parse_arguments()
{
   
    XDUMP_PACK_FLAG=0
    ALL_DUMP_FLAG=0
    ANDROID_BASE_DUMP_FLAG=0
    KERNEL_DUMP_FLAG=0
    DATA_DUMP_FLAG=0
    ANDROID_APK_DUMP_FLAG=0

    if [ $# -le 0 ]; then
        ALL_DUMP_FLAG=1
        XDUMP_PACK_FLAG=1
        return
    fi

    while getopts 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值