在遇到 monkey 执行完后概率性进程不退出(进程名 com.android.commands.monkey 变为 commands.monkey),就想要整体重新设计下。
加上最近提出要交付手工测试组执行,面临对于不懂 monekey 测试的人员也需要按计划完成专项测试。
我自己又给测试方式自提了新需求,于是整体思考重构了 monkey 压力测试及优化了 MCM 监控方案。

一、自提需求

1、按设定执行时间方式进行 monkey 测试

目的:避免无法按事件数预知准确时间,设定 monkey 压力测试 1 小时就是执行 1 小时测试。
方式:按 10000 事件数执行 monkey 测试,到设定时长则 kill monkey 进程,未达到则重复执行。

2、固定形式的 monkey 语句测试需按 case 形式维护

目的:由于交付的执行人员不一定懂 monkey,固定的执行写成 case 便于执行人员调用,同时也是简化主控制逻辑的维护方式。
方式:维护 case.sh 作为 moneky 执行方式的维护脚本
沿用:这里我沿用了之前想到要看下 mongkey 测试结束后等待一会(如 10 分钟),看下内存是否会继续上涨,就在设计时加入了测试结束后等待 10 分钟再停止应用;停止应用是为了避免之前测试后的状态影响下一个包的测试,就释放掉了进程。

3、将通用函数单独文件维护,将 shell 脚本的函数部分和控制部分非开维护。

目的:为了方便通用函数的复用,同时也是为了建立自己的一种写脚本模式。
方式:function.sh 维护全局变量和自定义函数,source 命令加载

4、组件形式的 app 需要侧重组件的界面进行压力测试,需要将显示的 activity 圈定在一定范围内。

目的:对于无法单包执行的组件 app,通过和依赖包一起测试完成压力测试需求。
方式:两个包进行测试,其中一个是调用组件的 app,另一个是独立的组件 app;monekey 执行后,使用一个子进程轮询判定 SurfaceFlinger 是否包含组件包名,如果不包含则使用长按键事件或 am start 组件 activity 的形式使组件画面显示;monekey 事件类型则只配操作不配置 appswitch。

5、把 MCM 监控方案优化维护,维护一个不需要 root 权限的版本。

目的:想增加自己设计的 MCM 监控方案的适用性
方式:使用 push busybox 到/data/local/tmp,调用此 busybox 命令进行脚本监控。

问题的解决

1、moneky 压力测试方案 V2.0

(1)全局变量及函数维护——function.sh
#!/system/bin/sh

########## Global Variable ##########
if [ -f /data/local/tmp/busybox ];then
    export bb="/data/local/tmp/busybox"
else
    echo "No /data/local/tmp/busybox"
    exit
fi
if [ -f /data/local/tmp/stop ];then
    $bb rm /data/local/tmp/stop
fi
#Test Result Folder
export testresult="/data/local/tmp/monkey"
if [ -d $testresult ];then
    $bb rm -r $testresult
fi
mkdir -p $testresult/log
#android version
export android=`getprop ro.build.version.release|$bb awk -F. '{print $1}'`
#root
export root=`id|$bb grep -c root`

########## Function ##########

#Add comments to comments.csv
comment(){
if [ ! -f $testresult/comments.csv ];then
    echo "Date,Tag,Comments,Info" >$testresult/comments.csv
fi
echo "`date +%m-%d" "%H":"%M":"%S`,$1,$2,$3" >>$testresult/comments.csv
}

#Create Log
c_log(){
if [ -f $testresult/error.pid ];then
    local E_pid=`$bb awk 'NR==1{print $NF}' $testresult/error.pid`
    if [ -d /proc/$E_pid ];then
        if [ $1 -eq 0 ];then
            comment "c_log" "error.pid is running, exit." "$E_pid"
            exit
        elif [ $1 -eq 1 ];then
            comment "c_log" "error.pid is running, kill." "$E_pid"
            kill -9 $E_pid 2>/dev/null
        fi
    else
        comment "c_log" "exist error.pid, not running" "$E_pid"
    fi
    $bb rm $testresult/error.pid
fi
if [ $1 -eq 0 ];then
    logcat -c
    if [ `cat /sys/devices/virtual/thermal/thermal_zone*/type|grep -c mtk` -eq 0 ];then
        logcat -v time -s AndroidRuntime:E ActivityManager:E DEBUG:F >$testresult/error.log &
    else
        logcat -v time -s AndroidRuntime:E ANRManager:E AEE/DEBUG:F >$testresult/error.log &
    fi
    local tmp=`$bb ps`
    echo "$tmp"|$bb grep "logcat -v time -s"|$bb awk 'NR==1{print $1}' >$testresult/error.pid
    comment "c_log" "Start error.pid." "`$bb awk 'NR==1{print $NF}' $testresult/error.pid`"
fi
}

#wait time between monkey test case
wait_time(){
local chek_begin=`$bb awk -F. 'NR==1{print $1}' /proc/uptime`
while true;do
    if [ $((`$bb awk -F. 'NR==1{print $1}' /proc/uptime`-chek_begin)) -ge $1 ];then
        break
    elif [ -f $testresult/monkey_error.txt ];then
        break
    else
        $bb sleep 5
    fi
done
}

########## monkey function ##########

#longpress to resume app.
#$1-keycode; $2-package name; $3-running time
longpress(){
local chek_begin=`$bb awk -F. 'NR==1{print $1}' /proc/uptime`
while true;do
    if [ $android -eq 6 ];then
        local tmp=`dumpsys SurfaceFlinger|$bb grep "|......|"`
    else
        local tmp=`dumpsys SurfaceFlinger|$bb grep "|....|"`
    fi
    if [ `echo "$tmp"|$bb grep -c "$2"` -eq 0 ];then
        input keyevent --longpress $1
    fi
    if [ $((`$bb awk -F. 'NR==1{print $1}' /proc/uptime`-chek_begin)) -ge $3 ];then
        break
    else
        $bb sleep 1
    fi
done
}

#longpress keycode 3 and 4 one by one: $1-package of keycode 3; $2-package of keycode 4; $3-sleep time; $4-running time
longkey(){
local l_key=3
local chek_begin=`$bb awk -F. 'NR==1{print $1}' /proc/uptime`
local package=$1
while true;do
    if [ $android -eq 6 ];then
        local tmp=`dumpsys SurfaceFlinger|$bb grep "|......|"`
    else
        local tmp=`dumpsys SurfaceFlinger|$bb grep "|....|"`
    fi
    if [ `echo "$tmp"|$bb grep -c "$package"` -eq 0 ];then
        input keyevent --longpress $l_key
    fi
    if [ $((`$bb awk -F. 'NR==1{print $1}' /proc/uptime`-chek_begin)) -ge $4 ];then
        break
    else
        $bb sleep $3
    fi
    case $l_key in
        3)
            local l_key=4
            local package=$2
        ;;
        4)
            local l_key=3
            local package=$1
        ;;
    esac
done
}

#longam to resume app.
#2 args: $1-package name; $2-running time;
#3 args: $1-package name; $2-running time; $3-activity(more than 1 activity: spilt by | . run them one by one);
longam(){
case $# in 
    2)
        local activity=`dumpsys activity $1|$bb grep ACTIVITY|$bb awk 'NR==1{print $2}'`
        local a_loops=1
    ;;
    3)
        local activity="$3"
        local a_loops=`echo "$3"|$bb awk -F"|" '{print NF}'`
    ;;
esac
if [ ! -z "$activity" ];then
    local chek_begin=`$bb awk -F. 'NR==1{print $1}' /proc/uptime`
    local i=1
    while true;do
        if [ $android -eq 6 ];then
            local tmp=`dumpsys SurfaceFlinger|$bb grep "|......|"`
        else
            local tmp=`dumpsys SurfaceFlinger|$bb grep "|....|"`
        fi
        if [ `echo "$tmp"|$bb grep -c "$1"` -eq 0 ];then
            if [ $a_loops -gt 1 ];then
                local activity="`echo "$3"|$bb awk -F"|" -v P=$i '{print $P}'`"
                if [ $i -lt $a_loops ];then
                    local i=$((i+1))
                else
                    local i=1
                fi
            fi
            local am_start=`am start $activity 2>&1`
            if [ `echo "$am_start"|$bb grep -c "Error"` -ne 0 ];then
                comment "longam" "am_error" "$am_start"
            fi
        fi
        if [ $((`$bb awk -F. 'NR==1{print $1}' /proc/uptime`-chek_begin)) -ge $2 ];then
            break
        else
            $bb sleep 1
        fi
    done
else
    comment "longam" "No activity" "$1"
    wait_time $2
fi
}

monkey_test(){
if [ -f $testresult/monkey_error.txt ];then
    $bb rm $testresult/monkey_error.txt
fi
case $# in
    3)
        sh /data/local/tmp/case.sh $1 $2 "$3" &
    ;;
    4)
        sh /data/local/tmp/case.sh $1 "$2" "$3" "$4" &
    ;;
    *)
        echo "Args are wrong!!!"
        exit
    ;;
esac
}

#if timeout, kill case.sh: $1-wait time
monkey_timeout(){
wait_time $(($1+600))
local chek_begin=`$bb awk -F. 'NR==1{print $1}' /proc/uptime`
while true;do
    local tmp=`$bb ps`
    if [ `echo "$tmp"|$bb grep -c case.sh` -ne 0 ];then
        if [ $((`$bb awk -F. 'NR==1{print $1}' /proc/uptime`-chek_begin)) -ge 60 ];then
            if [ -f $testresult/log.pid ];then
                local L_pid=`$bb awk 'NR==1{print $NF}' $testresult/log.pid`
                comment "monkey_timeout" "kill pid of log.pid." "$L_pid"
                kill -9 $L_pid 2>/dev/null
            fi
            if [ -f $testresult/kmsg.pid ];then
                local L_pid=`$bb awk 'NR==1{print $NF}' $testresult/kmsg.pid`
                comment "monkey_timeout" "kill pid of log.pid." "$L_pid"
                kill -9 $L_pid 2>/dev/null
            fi
            local pid=`echo "$tmp"|$bb grep "case.sh"|$bb awk '{print $1}'`
            if [ ! -z "$pid" ];then
                kill -9 `echo $pid`
            fi
            comment "monkey_timeout" "After waiting 60S, kill case.sh."
            break
        else
            comment "monkey_timeout" "case.sh not finish"
            $bb pkill com.android.commands.monkey
            $bb sleep 5
        fi
    else
        break
    fi
done
}
(2)monkey 执行维护 case——case.sh
#!/system/bin/sh

#args:
# type1 run case: $1-running time; $2-case id; $3-case arg
# type2 run monkey by "--pct":$1-running time; $2-(-p/-c); $3-(--pct); $4-the file name of monkey log.

if [ -f /data/local/tmp/busybox ];then
    bb="/data/local/tmp/busybox"
else
    echo "No /data/local/tmp/busybox"
    exit
fi

${testresult="/data/local/tmp/monkey"} 2>/dev/null
if [ ! -d $testresult/monkey_log ];then
    mkdir -p $testresult/monkey_log
fi
if [ ! -d $testresult/log ];then
    mkdir $testresult/log
fi
#android version
android=`getprop ro.build.version.release|$bb awk -F. '{print $1}'`
#root
root=`id|$bb grep -c root`

#Add comments to comments.csv
comment(){
if [ ! -f $testresult/comments.csv ];then
    echo "Date,Tag,Comments,Info" >$testresult/comments.csv
fi
echo "`date +%m-%d" "%H":"%M":"%S`,$1,$2,$3" >>$testresult/comments.csv
}

#lock or unlock screen.
#$1: 0--lock; 1--unlock
lock(){
${wm_size_x=`wm size|$bb awk -F" |x" '{print $(NF-1)}'`} 2>/dev/null
${wm_size_y=`wm size|$bb awk -F" |x" '{print $NF}'`} 2>/dev/null
while true;do
    if [ `cat /sys/class/leds/lcd-backlight/brightness` -eq 0 ];then
        if [ $1 -eq 0 ];then
            break
        else
            input keyevent 26&&$bb sleep 1&&input swipe $((v/2)) $((4*wm_size_y/5)) $((wm_size_x/2)) $((wm_size_y/5))
        fi
    else
        if [ $1 -eq 0 ];then
            input keyevent 26
        else
            if [ $android -eq 6 ];then
                local tmp=`dumpsys SurfaceFlinger|$bb grep "|......|"`
            else
                local tmp=`dumpsys SurfaceFlinger|$bb grep "|....|"`
            fi
            case `echo "$tmp"|$bb awk 'BEGIN{r="o"}{if($NF=="com.android.systemui.ImageWallpaper")r="l"}END{print NR-1 r}'` in
                "1o")
                    local state=0
                ;;
                "3l")
                    local state=1
                ;;
                *)
                    local state=2
                ;;
            esac
            if [ $state -eq 0 ];then
                input keyevent 26&&$bb sleep 1&&input swipe $((v/2)) $((4*wm_size_y/5)) $((wm_size_x/2)) $((wm_size_y/5))
            elif [ $state -eq 1 ];then
                input swipe $((wm_size_x/2)) $((4*wm_size_y/5)) $((wm_size_x/2)) $((wm_size_y/5))
            else
                break
            fi
        fi
    fi
    $bb sleep 1
done
}

#Create Log
C_log(){
if [ -f $testresult/log.pid ];then
    local L_pid=`$bb awk 'NR==1{print $NF}' $testresult/log.pid`
    if [ -d /proc/$L_pid ];then
        comment "C_log" "kill pid of log.pid." "$L_pid"
        kill -9 $L_pid 2>/dev/null
    else
        comment "C_log" "exist log.pid, not running" "$L_pid"
    fi
    if [ -f $testresult/kmsg.pid ];then
        local L_pid=`$bb awk 'NR==1{print $NF}' $testresult/kmsg.pid`
        if [ -d /proc/$L_pid ];then
            comment "C_log" "kill pid of kmsg.pid." "$L_pid"
            kill -9 $L_pid 2>/dev/null
        else
            comment "C_log" "exist kmsg.pid, not running" "$L_pid"
        fi
    fi
fi
if [ $root -eq 1 ];then
    cat /proc/kmsg >$testresult/log/$1.kmsg &
    echo $! >$testresult/kmsg.pid
fi
${logcat_type=`logcat --help 2>&1 |grep -c "\-T <count>"`} 2>/dev/null
if [ $logcat_type -eq 1 ];then
    logcat -v threadtime -b all -T 1 >$testresult/log/$1.log &
else
    logcat -c
    logcat -v threadtime >$testresult/log/$1.log &
fi
echo $! >$testresult/log.pid
}

save_log(){
if [ -f $testresult/log/$1.log ];then
    comment "save_log" "Start save" "$1"
    local time_name=`date +%Y%m%d%H%M%S`
    mkdir $testresult/log/$time_name
    $bb pstree -p >$testresult/log/$time_name/pstree.txt
    $bb top -b -n 1 >$testresult/log/$time_name/top.txt
    lock 1
    screencap -p $testresult/log/$time_name.png
    dmesg >$testresult/log/$time_name/dmesg.txt
    dumpsys dropbox --print >$testresult/log/$time_name/dropbox.txt
    cat /proc/meminfo >$testresult/log/$time_name/proc_meminfo.txt
    dumpsys meminfo >$testresult/log/$time_name/dumpsys_meminfo.txt
    if [ -f $testresult/log.pid ];then
        local L_pid=`$bb awk 'NR==1{print $NF}' $testresult/log.pid`
        if [ -d /proc/$L_pid ];then
            comment "save_log" "kill pid of log.pid." "$L_pid"
            kill -9 $L_pid 2>/dev/null
        else
            comment "save_log" "exist log.pid, not running" "$L_pid"
        fi
        if [ -f $testresult/kmsg.pid ];then
            local L_pid=`$bb awk 'NR==1{print $NF}' $testresult/kmsg.pid`
            if [ -d /proc/$L_pid ];then
                comment "save_log" "kill pid of kmsg.pid." "$L_pid"
                kill -9 $L_pid 2>/dev/null
            else
                comment "save_log" "exist kmsg.pid, not running" "$L_pid"
            fi
            $bb rm $testresult/kmsg.pid
        fi
        $bb rm $testresult/log.pid
    fi
    if [ $root -eq 1 ];then
        if [ ! -z "`ls /data/anr 2>/dev/null`" ];then
            $bb mv /data/anr/* $testresult/log/$time_name/
        fi
        if [ ! -z "`ls /data/tombstones 2>/dev/null`" ];then
            $bb mv /data/tombstones/* $testresult/log/$time_name
        fi
        if [ ! -z "`ls /data/system/dropbox/ 2>/dev/null`" ];then
            mkdir $testresult/log/$time_name/dropbox
            $bb mv /data/system/dropbox/* $testresult/log/$time_name/dropbox
        fi
        $bb tar -zcvf $testresult/log/$1_`date +%Y%m%d%H%M%S`.tar.gz -C $testresult/log $1.log $1.kmsg $time_name.png $time_name
        $bb rm $testresult/log/$1.kmsg
    else
        $bb tar -zcvf $testresult/log/$1_`date +%Y%m%d%H%M%S`.tar.gz -C $testresult/log $1.log $time_name.png $time_name
    fi
    $bb rm $testresult/log/$1.log $testresult/log/$time_name.png
    $bb rm -r $testresult/log/$time_name
    comment "save_log" "Finish save" "$1"
else
    comment "save_log" "Not Found" "$1"
fi
ls $testresult/log|grep log|$bb awk -F. '{print $1}' |while read T;do
    comment "save_log" "Found log" "$T"
    if [ $root -eq 1 ];then
        $bb tar -zcvf $testresult/log/$T.tar.gz -C $testresult/log $T.log $T.kmsg
        $bb rm $testresult/log/$T.kmsg
    else
        $bb tar -zcvf $testresult/log/$T.tar.gz -C $testresult/log $T.log
    fi
    $bb rm $testresult/log/$T.log
done
}

#wait time between monkey test case
wait_time(){
local log_n=`date +%Y%m%d%H%M%S`
C_log $log_n
local chek_begin=`$bb awk -F. 'NR==1{print $1}' /proc/uptime`
while true;do
    if [ $((`$bb awk -F. 'NR==1{print $1}' /proc/uptime`-chek_begin)) -ge $1 ];then
        break
    elif [ -f $testresult/monkey_error.txt ];then
        break
    else
        $bb sleep 1
    fi
done
save_log $log_n
}

#run monkey steps. 
run_monkey(){
$bb pkill com.android.commands.monkey
local log_n=0
local log_e=0
while [ $((`$bb awk -F. '{print $1}' /proc/uptime`-case_start_time)) -lt $1 ];do
    local tmp=`/system/bin/ps`
    local C_boot=`echo "$tmp"|$bb grep -c bootanimation`
    if [ $C_boot -eq 0 ];then
        local check=`echo "$tmp"|$bb grep -c com.android.commands.monkey`
        if [ $check -eq 0 ];then
            #check log
            if [ $log_n"a" != "0a" ];then
                save_log $log_n
            fi
            local log_n=`date +%Y%m%d%H%M%S`
            C_log $log_n
            lock 1
            comment "run_monkey" "$2" "Start test: $3 $1""S $4_$log_n"
            monkey $2 --throttle 500 --monitor-native-crashes $3 -v -v -v 2000 1>$testresult/monkey_log/$4_$log_n.txt 2>&1 &
            $bb sleep 3
            if [ `grep -c "No activities found to run, monkey aborted" $testresult/monkey_log/$4_$log_n.txt` -ne 0 ];then
                comment "run_monkey" "$2" "Error: No activities found to run, monkey aborted."
                save_log $log_n
                echo "$2 No activities" >$testresult/monkey_error.txt
                exit
            fi
        elif [ $check -eq 1 ];then
            #in activity contain "login", then press back.
            if [ $android -eq 6 ];then
                local tmp=`dumpsys SurfaceFlinger|$bb grep "|......|"`
            else
                local tmp=`dumpsys SurfaceFlinger|$bb grep "|....|"`
            fi
            if [ `echo "$tmp"|$bb grep -c "login"` -ne 0 ];then
                input keyevent 4
            elif [ `echo "$tmp"|$bb awk 'END{print NR}'` -eq 2 ];then
                lock 1
            fi
        #IF there are more than two monkey commands, kill all.
        elif [ $check -gt 1 ];then
            comment "run_monkey" "$2" "Error: $check monkey commands, killed!!!"
            $bb pkill com.android.commands.monkey
        fi
        $bb sleep 1
    else
        screencap -p $testresult/log/`date +%Y%m%d%H%M%S`.png
        comment "run_monkey" "bootanimation" "sleep 5"
        $bb sleep 5
    fi
done
$bb pkill com.android.commands.monkey
comment "run_monkey" "$2" "Finish test."
save_log $log_n
lock 0
}

#case
caselist(){
case "$1" in
    #test one package
    0)
        case "$3" in
            "com.letv.app.appstore"|"com.letv.games")
                run_monkey $2 "-p $3" "--pct-touch 20 --pct-trackball 5 --pct-motion 35 --pct-flip 5 --pct-appswitch 30 --pct-anyevent 5" "case$1_$3"
                wait_time 600
                am force-stop $3
            ;;
            "com.android.launcher3")
                run_monkey $2 "-p $3" "--pct-touch 20 --pct-trackball 10 --pct-motion 50 --pct-flip 5  --pct-appswitch 10 --pct-anyevent 5" "case$1_$3"
                wait_time 600
                am force-stop $3
            ;;
            "com.letv.android.quicksearchbox"|"com.letv.android.voiceassistant"|"com.google.android.googlequicksearchbox")
                run_monkey $2 "-p com.android.launcher3 -p $3" "--pct-touch 30 --pct-trackball 10 --pct-motion 45 --pct-flip 5 --pct-appswitch 5 --pct-anyevent 5" "case$1_$3"
                wait_time 600
                am force-stop $3
            ;;
            "com.letv.android.client"|"com.letv.android.letvlive"|"com.google.android.youtube"|"com.letv.internationalsarrs")
                run_monkey $2 "-p $3" "--pct-touch 10 --pct-trackball 10 --pct-motion 10 --pct-flip 10 --pct-appswitch 55 --pct-anyevent 5" "case$1_$3"
                wait_time 600
                am force-stop $3
            ;;
            "com.letv.lesophoneclient")
                run_monkey $2 "-p $3 -p com.letv.android.client" "--pct-touch 30 --pct-trackball 10 --pct-motion 45 --pct-flip 5 --pct-appswitch 5 --pct-anyevent 5" "case$1_$3"
                wait_time 600
                am force-stop $3
                am force-stop com.letv.android.client
            ;;
            "com.android.gallery3d"|"com.google.android.apps.photos"|"com.android.browser"|"com.android.chrome")
                run_monkey $2 "-p $3" "--pct-touch 10 --pct-trackball 10 --pct-motion 10 --pct-flip 5 --pct-appswitch 50 --pct-anyevent 5 --pct-pinchzoom 10" "case$1_$3"
                wait_time 600
                am force-stop $3
            ;;
            *)
                run_monkey $2 "-p $3" "--pct-touch 10 --pct-trackball 10 --pct-motion 10 --pct-flip 10 --pct-appswitch 55 --pct-anyevent 5" "case$1_$3"
                wait_time 600
                am force-stop $3
            ;;
        esac
    ;;
    #more than one package, appswitch 70%
    1)
        local packages=`echo "$3"|$bb awk -F "|" '{for(i=1;i<NF;i++)printf "-p "$i" ";printf "-p "$NF}'`
        run_monkey $2 "$packages" "--pct-touch 5 --pct-trackball 5 --pct-motion 10 --pct-flip 5 --pct-appswitch 70 --pct-anyevent 5" "case$1_appswitch70"
        wait_time 600
    ;;
    *)
        comment "caselist" "No case" "$1"
    ;;
esac
}

#main
case_start_time=`$bb awk -F. '{print $1}' /proc/uptime`
case $# in
    3)
        caselist $2 $1 "$3"
    ;;
    4)
        run_monkey $1 "$2" "$3" "$4"
    ;;
    *)
        comment "case" "Args are wrong!!!" "$*"
        exit
    ;;
esac
(3)主控逻辑——自定义名称.sh
#!/system/bin/sh

########## 初始设置 ##########

#加载全局变量和函数
source /data/local/tmp/function.sh
#创建ANR/FC/tombstone tag的异常log
c_log 0

########## 完成设置 ##########


########## monkey测试逻辑 ##########

# 执行实例:
# 方式1 执行case.sh已写好的case:$1时长?秒; $2-用例编号;$3-用例参数
# monkey_test 60 0 "com.letv.app.appstore"
# monkey_timeout 60 
# 方式2 按参数执行moneky语句:$1-时长; $2-限制范围;$3-事件比例; $4-monkey log文件名
# monkey_test 60 "-p com.letv.games" "--pct-touch 20 --pct-trackball 5 --pct-motion 35 --pct-flip 5 --pct-appswitch 30 --pct-anyevent 5" "letv_games"
# monkey_timeout 60 

#测试万象搜索
monkey_test 3600 0 "com.letv.android.quicksearchbox"
##将长按主页键对应操作修改为万象搜索,如果不显示万象搜索则长按唤起
longpress 3 "com.letv.android.quicksearchbox" 3600
#Monkey测试后锁屏10分钟
monkey_timeout 0
##保持am唤起主activity,间隔1S如不显示则唤起,由于“dumpsys activity 包名”获取不到乐搜activity传参
longam "com.letv.lesophoneclient" 3600 "com.letv.lesophoneclient/.ui.MainActivity"
monkey_timeout 0

########## monkey逻辑结束 ##########


########## 测试结束确保子进程已退出 ##########

#回收异常log进程
c_log 1

PID=`/system/bin/ps |grep $$|$bb awk -v pid=$$ '{if($2!=pid)print $2}'`
kill $PID
#通知停止监控
echo "`date +%m-%d" "%H":"%M":"%S` stop monitor scripts." > /data/local/tmp/stop
(4)MCM 监控方案脚本优化维护,统一为无 root,控制负载取消并发子进程方式,用类型控制是否获取 heap
#!/system/bin/sh
if [ -f /data/local/tmp/busybox ];then
    export bb="/data/local/tmp/busybox"
else
    echo "No /data/local/tmp/busybox"
    exit
fi
#参数判断
if [ $# -le 1 ];then
    echo "Args:$* is wrong!!!"
    exit
elif [ $# -eq 2 ];then
    packages="All"
elif [ $# -eq 3 ];then
    packages="$3"
fi
if [ -f /data/local/tmp/stop ];then
    $bb rm /data/local/tmp/stop
fi

#args:1-PID; 2-command; 3-Loop; 4-command args
getmem_pid(){
if [ -d /proc/$1 ];then
    local pss=`dumpsys meminfo $1|$bb awk -v pid=$1 -v comm=$2 -v loop=$3 '{if($1=="Uptime:")a=sprintf("%.3f",$2/1000);if($1=="**")comm=substr($6,2,length($6)-2);if($1=="Native"){n=n+$(NF-2);o=o+$(NF-1);p=p+$NF}else{if($1=="Dalvik"&&NF>6){d=d+$(NF-2);e=e+$(NF-1);f=f+$NF;g=g+$(NF-6)}else{if($1=="TOTAL"){print loop","a","pid","comm","$2+0","n+0","o+0","p+0","d+0","e+0","f+0","g+0}}}}'`
    if [ ! -z "$pss" ];then
        echo "$pss,\"$4\""
    fi
fi
}

get_package(){
local tmp=`dumpsys meminfo -c|$bb grep -E "time,|cat,"`
echo "$tmp"|$bb awk -F, '{if(NR==1){t=sprintf("%.3f",$2/1000)}else{if($1=="cat"){if(r=="")r=$3;else r=r","$3}}}END{print t","r}' >>$testresult/mem2.csv
local grep_str=`echo $packages|$bb sed 's/\./\\\\./g;s/\[/\\\[/g;s/\]/\\\]/g'`
local check=`/system/bin/ps|$bb grep -E "$grep_str"`
if [ ! -z "$check" ];then
    echo "$packages"|$bb sed 's/|/\n/g'|while read p;do
        echo "$check"|$bb awk -v package="$p" '{if($NF==package){t+=1;print $2" "$NF" "t}}'|while read l;do
            local pid=`echo $l|$bb awk '{print $1}'`
            if [ -f /proc/$pid/cmdline ];then
                local arg=`$bb awk 'BEGIN{r="null"}{if(NR>1){if(NR==2)r=$0;else r=r" "$0}}END{print r}' /proc/$pid/cmdline`
                if [ -z `echo $arg|$bb tr -d " "` ];then
                    local arg="null"
                fi
                getmem_pid $pid "`echo $l|$bb awk '{print $2}'`" $1 "$arg"
            fi
        done
    done
fi
}

get_meminfo(){
local tmp=`dumpsys meminfo -c|$bb grep -E -v ",grep,|,sh,|,dumpsys,"`
if [ ! -z "$tmp" ];then
    local uptime=`echo "$tmp"|$bb awk -F, 'NR==1{printf("%.3f",$2/1000)}'`
    echo "$tmp"|$bb awk -v time=$uptime -F, '$1=="cat"{if(r=="")r=$3;else r=r","$3}END{print time","r}' >>$testresult/mem2.csv
    local tmp=`echo "$tmp"|$bb grep -E "proc"`
    if [ $2 -eq 1 ];then
        echo "$tmp"|$bb grep ",native,"|while read l;do
            local pid=`echo $l|$bb awk -F, '{print $4}'`
            local comm=`echo $l|$bb awk -F, '{print $3}'`
            local pss=`echo $l|$bb awk -F, '{print $5}'`
            if [ ! -z "$pid" -a ! -z "$comm" -a ! -z "$pss" ];then
                if [ -f /proc/$pid/cmdline ];then
                    local arg=`$bb awk 'BEGIN{r="null"}{if(NR>1){if(NR==2)r=$0;else r=r" "$0}}END{print r}' /proc/$pid/cmdline`
                    if [ -z `echo $arg|$bb tr -d " "` ];then
                        local arg="null"
                    fi
                else
                    local arg="null"
                fi
                echo "$1,$uptime,$pid,$comm,$pss,,,,,,,,,\"$arg\""
            fi
        done
        local tmp=`echo "$tmp"|$bb grep -v ",native,"|$bb awk -F, '{print $4" "$3}'`
        echo "$tmp"|while read l;do
            getmem_pid $l $1 "null"
        done
    elif [ $2 -eq 0 ];then
        echo "$tmp"|while read l;do
            local pid=`echo $l|$bb awk -F, '{print $4}'`
            local comm=`echo $l|$bb awk -F, '{print $3}'`
            local pss=`echo $l|$bb awk -F, '{print $5}'`
            if [ ! -z "$pid" -a ! -z "$comm" -a ! -z "$pss" ];then
                if [ -f /proc/$pid/cmdline ];then
                    local arg=`$bb awk 'BEGIN{r="null"}{if(NR>1){if(NR==2)r=$0;else r=r" "$0}}END{print r}' /proc/$pid/cmdline`
                    if [ -z `echo $arg|$bb tr -d " "` ];then
                        local arg="null"
                    fi
                else
                    local arg="null"
                fi
                echo "$1,$uptime,$pid,$comm,$pss,\"$arg\""
            fi
        done
    fi
fi
}

getmem(){
local get_t=`$bb awk '{print $1}' /proc/uptime`
local info=`$bb awk 'BEGIN{r=0}{if($1=="MemFree:"){a=$2};if($1=="Buffers:"){b=$2};if($1=="Cached:"){c=$2};if($1=="Active:"){e=$2};if($1=="Inactive:"){f=$2};if($1=="Active(anon):"){g=$2};if($1=="Inactive(anon):"){h=$2};if($1=="Active(file):"){i=$2};if($1=="Inactive(file):"){j=$2};if($1=="Dirty:"){k=$2};if($1=="Writeback:"){l=$2};if($1=="Mapped:"){m=$2};if($1=="Slab:"){n=$2};if($1=="CMA"&&$2=="Free:"){r=1;a=a-$3;o=$3}}END{if(r==0) print a","b","c","e","f","g","h","i","j","k","l","m","n;else print a","b","c","e","f","g","h","i","j","k","l","m","n","o}' /proc/meminfo`
echo "$get_t,$info" >>$testresult/mem.csv
}

getcpu(){
local get_t=`$bb awk '{print $1}' /proc/uptime`
local activity=`dumpsys window w|$bb grep mFocusedApp|$bb awk '{print $5}'|$bb tr -d ',}'`
local data_t=`date +%Y/%m/%d" "%H:%M:%S`
local tmp=`$bb top -b -n 1|$bb grep -v "busybox"|$bb sed '2s/%//g;s/\\.0 / /g;s/ S N / SN /g;s/ R N / RN /g;s/ D N / DN /g;s/ Z N / ZN /g;s/ T N / TN /g;s/S </S</g;s/D </D</g;s/R </R</g;s/Z </Z</g;s/T </T</g;s/t </t</g;s/[0-9]m[0-9]/m /g;s/}/{/g;s/ th\\]/_th\\]/g;s/\\[mtk /\\[mtk_/g'|$bb awk -v data="$data_t" -v loop=$1 -v time="$get_t" -v act=$activity -v csv="$testresult/cpu.csv" -v csv2="$testresult/check.log" -v cpu=$2 -v T="{" -v T2="\"" '{if(NR==2) print loop","time","T2 act T2","$2","$4","$6","$8","$10","$12","$14","data >>csv;if(NR>4){r="";if($cpu=="0") exit;if($cpu+0==0){if($(cpu-1)/1000>0){a=sprintf("%.0f",$(cpu-1)/1000)}else{a=sprintf("%.1f",$(cpu-1))}c=substr($(cpu-1),length(a)+1);r=$cpu;if(NF>cpu);r=r T$(cpu+1)}else{if($(cpu+1)+0!=0){print $0 >>csv2}else{c=$cpu;r=$(cpu+1)}};if($(cpu+1)+0==0){if(NF>cpu+1){r=r T$(cpu+2);if(NF>cpu+2)r=r T$(cpu+3);if(NF>cpu+3)for(i=(cpu+4);i<=NF;i++)r=r" "$i};print loop","time","$1","c","r}}}'`
echo "$tmp"|$bb awk -F"{" -v S="}" -v T="\"" '{if(NF==1)print $0",,";if(NF==2)print $1","T$2T",";if(NF==3)print $1","T$2" "$3T",";if(NF==4&&$3=="")print $1$4",,"T$2T;if(NF==4&&$3!="")print $1","T$2" "$3S$4T",";if(NF>4&&$3==""){a=$5;if(NF>5)for(i=6;i<=NF;i++)a=a S $i;print $1$4","T a T","T$2T};if(NF>4&&$3!=""){a=$4;if(NF>4)for(i=5;i<=NF;i++)a=a S $i;print $1","T$2" "$3" "a T","}}' >>$testresult/cpuinfo.csv
}

#全局参数
testresult="/data/local/tmp/mcm_result"
if [ -f $testresult/state.txt ];then
    pid=`$bb awk -F "," '{print $1}' $testresult/state.txt`
    if [ -f /proc/$pid/cmdline ];then
        if [ `$bb awk 'NR==1{print $1}' /proc/$pid/cmdline`"a" == "sha" ];then
            echo "The $pid is sh command."
            exit
        fi
    fi
fi
if [ -d $testresult ];then
    $bb rm -r $testresult
fi
mkdir $testresult

mac=`cat /sys/class/net/*/address|$bb sed -n '1p'|$bb tr -d ':'`
model=`getprop ro.product.model|$bb sed 's/ /_/g'`
build=`getprop ro.build.fingerprint`
if [ -z $build ];then
    build=`getprop ro.build.description`
fi

start_time="`date +%Y/%m/%d" "%H:%M:%S`"
start_s=`$bb awk -F. '{print $1}' /proc/uptime`
echo "$$,$1,0/?,$model-$mac,$start_time,$start_s,$start_s,$build,$packages" >$testresult/state.txt
echo "Loop:$1,Time,Activity,usr,sys,nic,idle,io,irq,sirq,Data Time" >$testresult/cpu.csv
echo "Loop:$1,Time,PID,%CPU,Command,args,Thread" >$testresult/cpuinfo.csv
if [ `$bb grep -c "CMA Free" /proc/meminfo` -eq 0 ];then
    echo "Time:$1,MemFree,Buffers,Cached,Active,Inactive,Active(anon),Inactive(anon),Active(file),Inactive(file),Dirty,Writeback,Mapped,Slab" >$testresult/mem.csv
else
    echo "Time:$1,MemFree,Buffers,Cached,Active,Inactive,Active(anon),Inactive(anon),Active(file),Inactive(file),Dirty,Writeback,Mapped,Slab,CMA Free" >$testresult/mem.csv
fi
echo "Time:$1,"`dumpsys meminfo -c |$bb awk -F, '$1=="cat"{if(NR==1)r=$2;else r=r","$2}END{print r}'|$bb sed 's/ /_/g;s/\.//g'` >$testresult/mem2.csv
if [ $2 -eq 0 -a $# -eq 2 ];then
    echo "Loop:$1,Time,PID,Process_Name,Pss,Args" >$testresult/meminfo.csv
else
    echo "Loop:$1,Time,PID,Process_Name,Pss,Native_Heap(Size),Native_Heap(Alloc),Native_Heap(Free),Dalvik_Heap(Size),Dalvik_Heap(Alloc),Dalvik_Heap(Free),Dalvik_Pss,Args" >$testresult/meminfo.csv
fi
cpu_p=`$bb top -b -n 1|$bb awk 'NR==4{print NF-1}'`
loop=0
while true;do
    start_second=`$bb awk -F. '{print $1}' /proc/uptime`
    getcpu $loop $cpu_p
    getmem $loop
    if [ $# -eq 2 ];then
        get_meminfo $loop $2 >>$testresult/meminfo.csv
    elif [ $# -eq 3 ];then
        get_package $loop >>$testresult/meminfo.csv
    fi
    end_second=`$bb awk -F. '{print $1}' /proc/uptime`
    use_second=$((end_second-start_second))
    echo Use second: $use_second
    if [ -f /data/local/tmp/stop ];then
        echo "Found stop file!!!"
        break
    elif [ `$bb df /data|$bb awk '{r=substr($(NF-1),1,length($(NF-1))-1)}END{print r+0}'` -ge 90 ];then
        echo "The free space of data less 10%,stop!!!"
        break
    fi
    if [ $use_second -lt $1 ];then
        sleep $(($1-use_second))
    fi
    loop=$((loop+1))
    end_second=`$bb awk -F. '{print $1}' /proc/uptime`
    echo "$$,$1,$loop/?,$model-$mac,$start_time,$start_s,$end_second,$build,$packages" >$testresult/state.txt
done

更新维护

2016/06/08:

MCM 更新维护了脚本:
1、由于 le 全球化 CPU 内存监控改了双语模板
2、修改了几处数据展示错误

为了全球化解释方便 monkey 方案起了个名字 SCMF(Shell control Monkey Framework):
1、调整了 log 保存逻辑重构了之前按 10 秒筛查的逻辑,为了解决报 bug 时被反馈 log 不足情况
(1)保存 logcat 和 kmsg 按权限判定
(2)按时间戳保存 logcat 和 monkey log
(3)按 monkey 进程退出保存完整 log 进行打包压缩,命名按时间段命名 monkey/log 下
(4)按 tag 抓 ANR。FC,tombstone 的 log,兼容 mtk 和高通的不同 tag,按传感器名判断型号。用于后续筛查统计异常使用
(5)monkey 去除了去除异常继续执行的参数,以便退出后进行截图和当时 cpu,内存,进程信息抓取
2、填了些坑,如 system_server crash 判定,当发生 “软重启” 只截图停止 monkey 继续操作,timeout 时 case.sh 的子进程回收。

目前重构电量监控中,此版本没更新


↙↙↙阅读原文可查看相关链接,并与作者交流