系统UI压力测试,用脚本暴力Android系统界面

系统UI的稳定性是影响用户体验的关键因素。为了暴露在高频操作下的潜在问题,我编写了一个名为system_ui_storm.sh的脚本,它通过最直接、最暴力的方式对Android系统的关键界面进行高强度压力测试。这个脚本模拟用户对快速设置面板、通知栏和最近任务菜单进行疯狂操作,同时持续监控内存状态,旨在发现性能衰退、内存泄漏或响应失常等问题。

脚本从建立日志目录开始,确保所有输出都有记录。记录开始时间是为了控制总测试时长不超过2小时,避免无限运行。

#!/bin/bash
# system_ui_storm.sh
# 最直接、最暴力的系统UI压力测试

set -e

LOG_DIR="./stress_logs"
mkdir -p "$LOG_DIR"

# 记录开始时间
start_time=$(date +%s)
echo "测试开始时间: $(date)" > "$LOG_DIR/test.log"

 

快速设置测试函数循环1000次,每次先通过adb命令完全展开快速设置面板。这里调用两次expand-settings是因为第一次可能只展开快捷开关,第二次才展开详情视图。接着模拟点击屏幕上预设的多个坐标点,这些坐标覆盖了典型快速设置图标的常见位置。然后左右滑动以切换设置页面,最后收起面板。每50次循环记录一次内存快照,观察随着操作频次增加,systemui或system_server的内存占用是否出现异常增长。

test_quick_settings() {
    echo "==== 快速设置测试 ===="
    for i in {1..1000}; do
        echo "快速设置第 $i 次"
        
        # 下拉两次展开完整设置
        adb shell cmd statusbar expand-settings
        sleep 0.2
        adb shell cmd statusbar expand-settings
        sleep 0.5
        
        # 点击所有快速设置按钮
        positions=("200 300" "400 300" "600 300" 
                   "200 500" "400 500" "600 500"
                   "200 700" "400 700" "600 700")
        
        for pos in "${positions[@]}"; do
            adb shell input tap $pos
            sleep 0.1
        done
        
        # 滑动切换
        adb shell input swipe 600 400 200 400
        sleep 0.2
        
        # 收起
        adb shell cmd statusbar collapse
        sleep 0.5
        
        # 每50次记录内存
        if [ $((i % 50)) -eq 0 ]; then
            record_memory "quick_settings_$i"
        fi
    done
}

 

通知栏测试专注于下拉、滑动通知、点击通知操作以及清除所有通知。它模拟了一个完整的通知交互流程:展开后滑动列表,点击通知的可能操作区域(例如设置按钮),然后返回并最终清除所有通知。这个测试验证频繁展开/收起以及通知操作过程中,渲染和逻辑处理是否会出现卡顿或崩溃。

test_notification_shade() {
    echo "==== 通知栏测试 ===="
    for i in {1..500}; do
        echo "通知栏第 $i 次"
        
        # 下拉通知栏
        adb shell cmd statusbar expand-notifications
        sleep 0.5
        
        # 如果有通知,操作通知
        adb shell input swipe 500 600 500 300  # 滑动通知
        sleep 0.2
        adb shell input tap 800 500  # 点击设置按钮
        sleep 0.3
        adb shell input keyevent KEYCODE_BACK
        
        # 清除所有通知
        adb shell input tap 900 150
        sleep 0.2
        
        # 收起
        adb shell cmd statusbar collapse
        sleep 0.5
    done
}

 

最近任务测试是压力最大的场景之一。脚本先启动两个常用应用以填充后台,然后循环打开最近任务视图,在其中上下滑动浏览,随机点击一个应用返回前台,再回到桌面,最后尝试上滑清除所有任务。这个组合操作对系统的多任务管理逻辑、应用生命周期管理和界面渲染都是极大的考验,容易触发应用无响应或系统界面重启等问题。

test_recent_apps_stress() {
    echo "==== 最近任务压力测试 ===="
    # 先启动一些应用
    for app in com.android.chrome com.android.camera2; do
        adb shell monkey -p $app -c android.intent.category.LAUNCHER 1
        sleep 1
    done
    
    for i in {1..300}; do
        echo "最近任务第 $i 次"
        
        # 打开最近任务
        adb shell input keyevent KEYCODE_APP_SWITCH
        sleep 0.8
        
        # 滑动浏览
        adb shell input swipe 500 800 500 200
        sleep 0.3
        adb shell input swipe 500 200 500 800
        sleep 0.3
        
        # 尝试点击应用
        adb shell input tap 300 500
        sleep 0.5
        adb shell input keyevent KEYCODE_HOME
        sleep 0.5
        
        # 清除所有
        adb shell input swipe 500 1500 500 100
        sleep 0.5
    done
}

 

内存监控函数是评估测试效果的关键。它不仅抓取system_server进程的详细内存信息(这是系统UI服务的核心),还记录整体内存状况和进程内存排名。通过对比不同时间点的内存快照,可以清晰判断是否有内存泄漏发生。数据被同时记录到带有时间戳的详细文件和一份汇总日志中,便于追踪和对比。

record_memory() {
    local tag=$1
    local timestamp=$(date +"%Y%m%d_%H%M%S")
    
    echo "=== 内存记录 $tag ===" >> "$LOG_DIR/memory.log"
    
    # system_server内存
    adb shell dumpsys meminfo system_server >> "$LOG_DIR/memory_${timestamp}.txt"
    
    # 整体内存
    adb shell cat /proc/meminfo >> "$LOG_DIR/memory_${timestamp}.txt"
    
    # 进程内存排名
    echo "=== 进程内存排名 ===" >> "$LOG_DIR/memory_${timestamp}.txt"
    adb shell procrank | head -20 >> "$LOG_DIR/memory_${timestamp}.txt"
    
    # 记录到总日志
    echo "$timestamp - $tag" >> "$LOG_DIR/memory.log"
    adb shell dumpsys meminfo | grep -E "Used RAM:|Free RAM:|Lost RAM:" >> "$LOG_DIR/memory.log"
    echo "----" >> "$LOG_DIR/memory.log"
}

 

主循环控制整个测试流程,设定总运行时长为2小时。它将三个核心测试函数放在后台并行执行,以模拟用户多任务操作的混乱场景,这比串行测试更能制造压力。每一轮测试结束后,脚本会主动向systemui发送修剪内存的命令,模拟系统在内存紧张时的回收行为,然后等待10秒开始下一轮。这种设计是为了在长时间运行中观察内存和性能的累积效应。

# 主测试循环
while true; do
    current_time=$(date +%s)
    duration=$((current_time - start_time))
    
    # 测试2小时
    if [ $duration -gt 7200 ]; then
        echo "测试时间到,结束"
        break
    fi
    
    echo "=== 开始新一轮测试,已运行 $((duration/60)) 分钟 ==="
    
    # 并行运行不同测试
    test_quick_settings &
    pid1=$!
    
    test_notification_shade &
    pid2=$!
    
    test_recent_apps_stress &
    pid3=$!
    
    # 等待所有测试完成
    wait $pid1 $pid2 $pid3
    
    # 强制GC一次
    adb shell am send-trim-memory com.android.systemui RUNNING_CRITICAL
    
    echo "=== 一轮测试完成,等待10秒 ==="
    sleep 10
done

测试结束时,脚本会抓取最终的内存信息和内核日志的最后部分。这些最终状态数据与测试过程中记录的日志共同构成了分析问题的完整证据链,可以用于定位是哪个特定操作序列导致了系统UI的异常。

# 最终内存快照
echo "=== 最终状态 ===" >> "$LOG_DIR/test.log"
adb shell dumpsys meminfo >> "$LOG_DIR/final_memory.txt"
adb shell dmesg | tail -100 >> "$LOG_DIR/final_dmesg.txt"

echo "测试完成,日志保存在 $LOG_DIR/"

完整代码

#!/bin/bash
# system_ui_storm.sh
# 最直接、最暴力的系统UI压力测试

set -e

LOG_DIR="./stress_logs"
mkdir -p "$LOG_DIR"

start_time=$(date +%s)
echo "测试开始时间: $(date)" > "$LOG_DIR/test.log"

test_quick_settings() {
    echo "==== 快速设置测试 ===="
    for i in {1..1000}; do
        echo "快速设置第 $i 次"
        adb shell cmd statusbar expand-settings
        sleep 0.2
        adb shell cmd statusbar expand-settings
        sleep 0.5
        positions=("200 300" "400 300" "600 300" 
                   "200 500" "400 500" "600 500"
                   "200 700" "400 700" "600 700")
        for pos in "${positions[@]}"; do
            adb shell input tap $pos
            sleep 0.1
        done
        adb shell input swipe 600 400 200 400
        sleep 0.2
        adb shell cmd statusbar collapse
        sleep 0.5
        if [ $((i % 50)) -eq 0 ]; then
            record_memory "quick_settings_$i"
        fi
    done
}

test_notification_shade() {
    echo "==== 通知栏测试 ===="
    for i in {1..500}; do
        echo "通知栏第 $i 次"
        adb shell cmd statusbar expand-notifications
        sleep 0.5
        adb shell input swipe 500 600 500 300
        sleep 0.2
        adb shell input tap 800 500
        sleep 0.3
        adb shell input keyevent KEYCODE_BACK
        adb shell input tap 900 150
        sleep 0.2
        adb shell cmd statusbar collapse
        sleep 0.5
    done
}

test_recent_apps_stress() {
    echo "==== 最近任务压力测试 ===="
    for app in com.android.chrome com.android.camera2; do
        adb shell monkey -p $app -c android.intent.category.LAUNCHER 1
        sleep 1
    done
    for i in {1..300}; do
        echo "最近任务第 $i 次"
        adb shell input keyevent KEYCODE_APP_SWITCH
        sleep 0.8
        adb shell input swipe 500 800 500 200
        sleep 0.3
        adb shell input swipe 500 200 500 800
        sleep 0.3
        adb shell input tap 300 500
        sleep 0.5
        adb shell input keyevent KEYCODE_HOME
        sleep 0.5
        adb shell input swipe 500 1500 500 100
        sleep 0.5
    done
}

record_memory() {
    local tag=$1
    local timestamp=$(date +"%Y%m%d_%H%M%S")
    echo "=== 内存记录 $tag ===" >> "$LOG_DIR/memory.log"
    adb shell dumpsys meminfo system_server >> "$LOG_DIR/memory_${timestamp}.txt"
    adb shell cat /proc/meminfo >> "$LOG_DIR/memory_${timestamp}.txt"
    echo "=== 进程内存排名 ===" >> "$LOG_DIR/memory_${timestamp}.txt"
    adb shell procrank | head -20 >> "$LOG_DIR/memory_${timestamp}.txt"
    echo "$timestamp - $tag" >> "$LOG_DIR/memory.log"
    adb shell dumpsys meminfo | grep -E "Used RAM:|Free RAM:|Lost RAM:" >> "$LOG_DIR/memory.log"
    echo "----" >> "$LOG_DIR/memory.log"
}

while true; do
    current_time=$(date +%s)
    duration=$((current_time - start_time))
    if [ $duration -gt 7200 ]; then
        echo "测试时间到,结束"
        break
    fi
    echo "=== 开始新一轮测试,已运行 $((duration/60)) 分钟 ==="
    test_quick_settings &
    pid1=$!
    test_notification_shade &
    pid2=$!
    test_recent_apps_stress &
    pid3=$!
    wait $pid1 $pid2 $pid3
    adb shell am send-trim-memory com.android.systemui RUNNING_CRITICAL
    echo "=== 一轮测试完成,等待10秒 ==="
    sleep 10
done

echo "=== 最终状态 ===" >> "$LOG_DIR/test.log"
adb shell dumpsys meminfo >> "$LOG_DIR/final_memory.txt"
adb shell dmesg | tail -100 >> "$LOG_DIR/final_dmesg.txt"
echo "测试完成,日志保存在 $LOG_DIR/"

使用教程

  1. 确保测试设备已通过USB连接电脑,并已开启USB调试模式。
  2. 将上述完整代码保存为system_ui_storm.sh文件。
  3. 在终端中,进入脚本所在目录,执行chmod +x system_ui_storm.sh赋予脚本执行权限。
  4. 运行./system_ui_storm.sh开始测试。
  5. 测试期间请勿操作设备,脚本会自动执行所有测试步骤。
  6. 测试完成后,所有日志会保存在当前目录下的stress_logs文件夹中。
  7. 重点分析memory.log文件查看内存变化趋势,检查final_memory.txtfinal_dmesg.txt查看最终状态和内核错误信息。
THE END
喜欢就支持一下吧
赞赏 分享