10.1 自动化功耗测试脚本
手动测功耗?说实话,一次两次还行,迭代个几十次你肯定崩溃。我习惯写一个 shell 脚本,把整个流程串起来。
先看一个最基础的脚本框架:
#!/bin/bash # 自动化功耗采集脚本 - 基础版 DEVICE_SERIAL="your_device_serial" OUTPUT_DIR="./power_data" TIMESTAMP=$(date +%Y%m%d_%H%M%S) # 创建输出目录 mkdir -p $OUTPUT_DIR # 1. 清除旧数据 adb -s $DEVICE_SERIAL shell dumpsys batterystats --reset # 2. 启动待测场景 echo "启动待测场景..." adb -s $DEVICE_SERIAL shell am start -W com.example.app/.MainActivity # 3. 等待场景稳定(我一般等5秒) sleep 5 # 4. 开始采集 echo "开始采集功耗数据..." for i in {1..10}; do adb -s $DEVICE_SERIAL shell dumpsys power > $OUTPUT_DIR/power_${TIMESTAMP}_${i}.txt sleep 2 done # 5. 采集电池统计 adb -s $DEVICE_SERIAL shell dumpsys batterystats > $OUTPUT_DIR/battery_${TIMESTAMP}.txt echo "采集完成,数据保存在 $OUTPUT_DIR"这个脚本干了五件事:重置数据、启动应用、等待稳定、循环采集、保存结果。
每次采集前先执行adb shell dumpsys batterystats --reset,不然你会拿到一堆历史数据,根本分不清哪些是当前场景的。
10.2 adb shell dumpsys power 深度解析
adb shell dumpsys power会输出一大堆东西。我帮你拆解一下核心字段:
| 字段 | 含义 | 重点关注 |
|---|---|---|
| mWakefulness | 设备唤醒状态 | Asleep 表示休眠,Awake 表示唤醒 |
| mScreenOn | 屏幕是否点亮 | true 时功耗会高很多 |
| mWakeLocks | 当前持有的唤醒锁 | 这里经常有异常持锁的情况 |
| mDisplayPowerState | 显示电源状态 | ON/OFF/DOZE 三种状态 |
| mBatteryLevel | 当前电量百分比 | 用于计算功耗变化 |
为什么会关注 mWakeLocks?我在项目里遇到过,某个第三方 SDK 在后台持了一个 PARTIAL_WAKE_LOCK,导致设备无法进入深度休眠。一晚上掉电 30%,用户直接炸了。
避坑指南:我曾经因为没注意 mWakefulness 字段,采集了一堆"假数据"。设备其实已经休眠了,但我以为还在跑测试场景。采集前先检查 mWakefulness 是不是预期的状态。
10.3 功耗数据格式化与存储
原始数据是文本,没法直接分析。我一般会写个 Python 脚本做格式化:
import re import json from datetime import datetime def parse_power_dump(raw_text): """解析 dumpsys power 输出""" result = {} # 提取唤醒状态 wake_match = re.search(r'mWakefulness=(\w+)', raw_text) if wake_match: result['wakefulness'] = wake_match.group(1) # 提取屏幕状态 screen_match = re.search(r'mScreenOn=(\w+)', raw_text) if screen_match: result['screen_on'] = screen_match.group(1) == 'true' # 提取唤醒锁 locks = re.findall(r'Lock\{(.+?)\}', raw_text) result['wake_locks'] = locks # 提取电量 battery_match = re.search(r'mBatteryLevel=(\d+)', raw_text) if battery_match: result['battery_level'] = int(battery_match.group(1)) # 添加时间戳 result['timestamp'] = datetime.now().isoformat() return result # 使用示例 with open('power_20240101_120000_1.txt', 'r') as f: raw = f.read() parsed = parse_power_dump(raw) print(json.dumps(parsed, indent=2, ensure_ascii=False))格式化之后的数据长这样:
{ "wakefulness": "Awake", "screen_on": true, "wake_locks": [ "PARTIAL_WAKE_LOCK:com.example.app" ], "battery_level": 85, "timestamp": "2024-01-01T12:00:05" }我习惯存成 JSON 格式,方便后续做趋势分析。你想想看,如果你有 100 次测试的数据,用 JSON 存起来,写个脚本就能画出功耗曲线图,多直观。
存储建议:
- 按日期建文件夹,比如
power_data/2024/01/01/ - 文件名包含场景标识,比如
video_playback_001.json - 每个 JSON 文件包含元数据:设备型号、系统版本、测试场景
10.4 完整的数据采集流程
把上面这些串起来,就是一个完整的自动化流程:
#!/bin/bash # 完整版自动化采集脚本 SCENE=$1 # 场景名称,比如 "video_playback" DURATION=$2 # 采集时长,单位秒 OUTPUT_BASE="./power_data/$(date +%Y/%m/%d)" mkdir -p $OUTPUT_BASE echo "=== 开始采集: $SCENE ===" # 重置电池统计 adb shell dumpsys batterystats --reset # 启动场景 adb shell am start -W com.example.app/.$SCENE sleep 3 # 循环采集 END=$((SECONDS + DURATION)) while [ $SECONDS -lt $END ]; do TIMESTAMP=$(date +%H%M%S) adb shell dumpsys power > $OUTPUT_BASE/${SCENE}_${TIMESTAMP}.txt # 顺便采集电池详情 adb shell dumpsys batterystats > $OUTPUT_BASE/${SCENE}_battery_${TIMESTAMP}.txt sleep 2 done echo "=== 采集完成 ===" echo "数据保存在: $OUTPUT_BASE"使用方式:
./collect_power.sh video_playback 60这条命令会采集 60 秒的视频播放功耗数据,每 2 秒一次快照。我个人觉得这个频率比较合适,太快了数据冗余,太慢了抓不到关键变化。
小技巧:采集完成后,用adb shell dumpsys batterystats --reset再清一次数据,避免影响下一次测试。我吃过这个亏,两次测试的数据混在一起,排查了半天。
10.5 知识体系总览
下面这张图帮你理清本章的核心逻辑: