ADB操作Android电池信息:从获取到模拟测试的完整指南
1. 项目缘起为什么需要从ADB层面操作电池信息在Android应用开发或者设备测试的日常工作中我们经常会遇到一些与设备电量相关的棘手场景。比如你正在开发一个需要深度优化功耗的App或者在进行自动化测试时需要模拟设备在不同电量下的行为例如低电量告警、省电模式触发。如果仅仅依赖应用层API你会发现限制颇多很多底层的、实时的电池状态信息无法获取更别提去主动设置或模拟某些状态了。这时Android Debug Bridge也就是我们常说的ADB就成为了一个强大的“后门”。它允许我们绕过应用层的限制直接与Android系统的底层服务进行交互。通过ADB获取电池信息我们能拿到比BatteryManagerAPI更原始、更丰富的数据而“设置”电池信息的能力则主要服务于测试场景比如在自动化测试框架中伪造一个“电量即将耗尽”的状态来验证应用的降级逻辑是否正常触发。简单来说这个技能点属于“平时用不到用到就是宝”的类型。它连接了应用开发、系统测试和性能调优等多个环节。接下来我就结合自己踩过的坑和实际项目经验带你从零开始彻底搞懂如何通过ADB玩转电池信息。2. 环境准备与核心工具链梳理在开始实操之前确保你的“武器库”是齐全且配置正确的。很多新手卡在第一步问题都出在环境上。2.1 ADB工具的正确安装与连接验证首先你需要ADB工具。它包含在Android SDK Platform-Tools中。最稳妥的方式是去Android开发者官网下载独立的Platform-Tools包解压后将其路径例如D:\android-sdk\platform-tools添加到系统的PATH环境变量中。我不推荐使用某些第三方打包的“绿色版”或国内论坛下载的版本它们可能版本老旧或带有未知修改在执行一些需要特定权限的命令时可能出问题。安装后打开终端Windows的CMD/PowerShell macOS/Linux的Terminal输入adb version来验证。接下来是最关键的一步连接设备。连接真机在手机的“开发者选项”中开启“USB调试”。用数据线连接电脑后在终端输入adb devices。如果设备列表中出现你的设备并显示device状态说明连接成功。如果显示unauthorized你需要在手机弹出的“允许USB调试”对话框中点击确认。连接模拟器对于Android Studio自带的模拟器或MuMu、夜神等第三方模拟器ADB通常会自动连接。同样使用adb devices查看模拟器会以127.0.0.1:端口号的形式列出例如127.0.0.1:7555。注意如果你同时连接了多个设备比如一台真机和一个模拟器在执行后续ADB命令时需要指定目标设备使用-s 设备序列号参数例如adb -s emulator-5554 shell ...。否则ADB会随机选择一个设备导致操作对象错误。2.2 理解ADB Shell与系统属性我们操作电池信息的核心战场是在adb shell环境中。adb shell命令让我们能进入连接设备的Linux命令行界面。电池信息在Android系统中主要通过两种机制暴露Linux内核的Power Supply子系统信息存储在/sys/class/power_supply/目录下的虚拟文件中。这是最底层的数据源。Android系统的BatteryService它从内核读取信息进行加工处理后存储在系统属性system properties和通过Binder服务提供给上层。我们通过dumpsys命令访问的就是这个服务。因此你需要熟悉几个关键的Shell命令cat查看文件内容用于读取/sys/class/power_supply/下的文件。dumpsys转储dump系统服务的信息功能极其强大。getprop/setprop获取和设置系统属性。但请注意绝大多数系统属性是只读的尤其是像电池状态这种关键信息普通ADB Shell无root无法直接修改。所谓的“设置”电池信息通常需要通过其他间接手段模拟。3. 深度获取多种途径解析电池全量信息获取信息不是简单地跑一个命令理解每条数据背后的含义和来源更重要。下面我分层次介绍。3.1 黄金标准使用dumpsys battery命令这是最常用、信息最全的方式。在adb shell中直接输入adb shell dumpsys battery你会看到类似下面的输出不同设备、系统版本可能略有差异Current Battery Service state: AC powered: false USB powered: true Wireless powered: false Max charging current: 3000000 Max charging voltage: 9000000 Charge counter: 3500000 status: 2 health: 2 present: true level: 85 scale: 100 voltage: 4301 temperature: 320 technology: Li-ion我们来逐条解析关键字段这比单纯看数字有用得多AC powered/USB powered/Wireless powered当前充电类型。这是判断充电状态最直接的布尔值。status电池状态码。这是一个关键数字你需要知道它的含义1未知2充电中3放电中4未充电5满电health电池健康状态码。2良好3过热4已损坏或电压异常5过电压6未知错误levelscale当前电量水平和最大刻度。电量百分比 level/scale* 100。这里scale几乎总是100。voltage当前电池电压单位是毫伏mV。示例中的4301表示4.301V。temperature电池温度单位是0.1摄氏度。示例中的320表示32.0°C。这是一个非常重要的监控指标温度过高是电池老化或存在问题的信号。technology电池技术如Li-ion锂离子、Li-poly锂聚合物。Charge counter电荷计数器单位是微安时μAh可以用于估算电池容量但需要结合设计容量来分析。实操心得在自动化脚本中我通常不会解析整个文本输出而是使用grep和cut等命令提取特定字段。例如只获取电量百分比adb shell dumpsys battery | grep level | awk {print $2}。在Windows的CMD中可能需要借助findstr。3.2 底层窥探查看/sys/class/power_supply/目录对于想要深入研究或某些dumpsys信息不全的定制系统可以直接查看内核数据。首先进入该目录查看有哪些电源设备adb shell ls -l /sys/class/power_supply/你可能会看到batteryusbwireless等目录。对于电池我们关心battery/下的文件。adb shell cat /sys/class/power_supply/battery/capacity # 当前电量百分比 adb shell cat /sys/class/power_supply/battery/status # 状态 (Charging, Discharging, Full等) adb shell cat /sys/class/power_supply/battery/health # 健康状态 adb shell cat /sys/class/power_supply/battery/temp # 温度 (单位可能是0.1摄氏度或直接是摄氏度需验证) adb shell cat /sys/class/power_supply/battery/voltage_now # 当前电压 (微伏 uV) adb shell cat /sys/class/power_supply/battery/current_now # 当前电流 (微安 uA正值表示放电负值表示充电)重要区别这里的数据更“原始”。例如capacity可能和dumpsys的level一致但voltage_now的单位是微伏(μV)而dumpsys中是毫伏(mV)。电流值在这里可以直接获取而dumpsys通常不直接提供实时电流。3.3 快捷查询使用adb shell getprop命令一些电池信息也会被缓存在系统属性中但不如前两者全面和实时。adb shell getprop | grep battery可能会看到像[ro.boot.fake_battery]: [0]或[sys.boot_completed]: [1]这类属性直接相关的电池状态属性较少。dumpsys仍然是首选。4. “设置”电池信息的真相与实战模拟方法这是标题中最具迷惑性也最需要谨慎操作的部分。在非Root的普通调试环境下你无法直接、永久地修改手机真实的物理电池状态。所谓的“设置”实质上是对Android系统的BatteryService进行“欺骗”让它以为电池处于某种状态从而影响系统的行为如触发低电量广播、进入省电模式。这个功能主要服务于自动化测试。4.1 官方测试命令adb shell dumpsys batteryAndroid本身提供了用于测试的“设置”命令但它修改的是BatteryService在内存中的状态重启服务或设备后会重置。设置电量百分比模拟低电量adb shell dumpsys battery set level 数值例如模拟电量只剩15%adb shell dumpsys battery set level 15。执行后系统会立即广播ACTION_BATTERY_CHANGED你的应用如果监听了这个广播就会收到电量变化通知。状态栏的电量图标也会相应变化在某些系统版本上可能不会立即刷新UI但广播已发出。设置充电状态adb shell dumpsys battery set ac|usb|wireless|status 状态设置AC充电adb shell dumpsys battery set ac 1(1开启0关闭)设置USB充电adb shell dumpsys battery set usb 1设置无线充电adb shell dumpsys battery set wireless 1直接设置状态码adb shell dumpsys battery set status 2/3/4/5(对应充电、放电、未充电、满电)重置为真实状态测试完成后务必重置让系统恢复读取真实硬件数据adb shell dumpsys battery reset4.2 进阶模拟使用adb shell cmd命令在Android 10API 29及以上版本Google引入了更规范的cmd命令来与系统服务交互。操作电池服务的命令如下adb shell cmd battery set level 数值 adb shell cmd battery set status 状态码 adb shell cmd battery set ac|usb|wireless 0或1 adb shell cmd battery reset其效果与dumpsys battery set基本一致但这是更推荐的新接口。4.3 重要警告与局限性仅影响软件层面这些命令只欺骗了Android框架层。手机的真实硬件电量、充电电路完全不受影响。拔掉充电器用dumpsys battery set ac 1模拟的AC充电状态依然存在但实际硬件并未充电。UI可能不同步虽然广播发出了但SystemUI状态栏更新可能滞后或不更新这取决于手机厂商的系统定制。不要以状态栏图标作为测试成功的唯一标准应以应用日志中收到的广播或BatteryManagerAPI读取到的值为准。需要后台测试权限在Android PieAPI 28以后应用对电池状态信息的访问受到了限制。你的测试应用可能需要声明REQUEST_IGNORE_BATTERY_OPTIMIZATIONS权限或在后台运行时能够正常接收广播这需要在测试代码中处理好。无法模拟所有属性像health健康状态、temperature温度等属性通常无法通过上述简单命令设置。模拟这些需要更复杂的方法例如使用可注入测试数据的模拟器如Android Studio模拟器支持扩展控制面板设置电池温度或者在拥有Root权限的设备上直接修改对应的系统文件或属性。5. 自动化测试集成实战案例理论说再多不如看一个实际的应用场景。假设我们要为一个音乐播放器App编写一个自动化测试用例“当电量低于20%且未在充电时应自动暂停播放并弹出省电提示”。我们使用Python脚本结合adb命令和uiautomator2一个流行的Android UI自动化框架来模拟这个场景。import subprocess import time import uiautomator2 as u2 def set_battery_via_adb(level, chargingFalse): 通过ADB设置电池状态 # 重置确保状态干净 subprocess.run([adb, shell, dumpsys, battery, reset], capture_outputTrue) time.sleep(0.5) # 设置电量水平 subprocess.run([adb, shell, dumpsys, battery, set, level, str(level)], capture_outputTrue) # 设置充电状态 if charging: subprocess.run([adb, shell, dumpsys, battery, set, ac, 1], capture_outputTrue) else: subprocess.run([adb, shell, dumpsys, battery, set, ac, 0], capture_outputTrue) subprocess.run([adb, shell, dumpsys, battery, set, status, 3], capture_outputTrue) # 放电状态 time.sleep(1) # 等待系统广播生效 print(f模拟设置完成电量{level}%充电状态{charging}) def test_low_battery_behavior(): # 连接设备 d u2.connect() app_package com.example.musicplayer # 1. 启动应用并开始播放音乐 d.app_start(app_package) time.sleep(2) d(resourceIdcom.example.musicplayer:id/play_button).click() print(音乐开始播放...) time.sleep(3) # 2. 模拟电量降至15%且未充电 set_battery_via_adb(15, chargingFalse) # 3. 等待并验证应用行为 time.sleep(3) # 给应用反应时间 # 检查是否弹出提示框假设其文本包含“省电” if d(textContains省电).exists(timeout5): print(✓ 低电量提示框成功弹出。) else: print(✗ 未检测到低电量提示框可能逻辑有误或元素定位失败。) # 检查音乐是否暂停假设暂停按钮状态变化 # 这里需要根据实际App的UI元素来判断 # 例如播放按钮重新变为可点击状态 if d(resourceIdcom.example.musicplayer:id/play_button).get_text() 播放: print(✓ 音乐已自动暂停。) else: print(✗ 音乐可能未暂停。) # 4. 清理重置电池状态停止应用 subprocess.run([adb, shell, dumpsys, battery, reset]) d.app_stop(app_package) print(测试结束环境已清理。) if __name__ __main__: test_low_battery_behavior()脚本解析与避坑点重置的重要性在每次设置前先reset避免之前测试的残留状态影响本次测试。状态同步延迟设置命令发出后系统广播和App响应需要时间。time.sleep(1)是简单的等待在生产级测试框架中应使用更智能的等待条件如等待特定UI元素出现。UI元素定位uiautomator2通过资源ID、文本等方式定位元素。你需要使用adb shell uiautomator dump或App的布局检查工具来获取正确的元素标识。这是UI自动化中最容易出错的部分。广播接收验证更严谨的测试应该在App内部打日志或者通过logcat过滤特定的广播接收日志来验证这比依赖UI更可靠。6. 高级议题与疑难排查当你掌握了基础操作后可能会遇到更复杂的需求或问题。6.1 模拟电池温度与健康状态如前所述标准adb shell dumpsys battery set命令不支持设置温度和健康度。如果你确实需要测试高温保护或电池损坏的场景有以下几种途径使用Android Studio模拟器这是最方便的选择。在模拟器的扩展控制面板Extended Controls中可以直接滑动设置电池温度和健康状态Good, Failed, Dead等。这完全在软件层面模拟非常适合CI/CD集成测试。Root设备在已Root的设备上你可以尝试直接向底层接口写入数据。例如某些设备上温度信息存储在/sys/class/power_supply/battery/temp文件中理论上可以echo一个值进去但极其危险且强烈不推荐可能破坏系统或需要内核支持每台设备路径和格式都可能不同。Mock系统服务在单元测试或插桩测试Instrumentation Test中你可以使用AndroidX Test提供的BatteryMocks或自己创建Mock对象来模拟BatteryManager的返回值和广播。这是面向代码层级的、更安全的测试方法。6.2 排查“设置”无效的常见原因如果你发现adb shell dumpsys battery set level 10之后你的App没反应可以按以下步骤排查确认命令生效首先立即执行adb shell dumpsys battery检查level和status字段是否已经变成了你设置的值。如果这里都没变说明命令执行有问题可能是设备未连接好或Shell权限问题。检查广播在终端运行adb logcat | grep -i battery_changed然后再次执行设置命令。观察日志中是否有ACTION_BATTERY_CHANGED广播被发出的记录。如果没有可能是系统版本或定制ROM的问题。验证App监听器确保你的App正确注册了ACTION_BATTERY_CHANGED广播接收器动态注册或静态注册并且没有因为进程被杀、省电策略等原因失效。可以在App代码里收到广播后打印一条Log便于追踪。检查后台限制在Android 6.0App进入待机模式Doze后会被限制网络和后台作业Android 8.0对后台服务有严格限制Android 10限制了后台启动Activity。确保你的测试场景避开了这些限制或者为测试应用申请了相应的豁免权限。厂商定制一些国内手机厂商的深度定制系统如MIUI、EMUI可能会修改电池相关的广播行为或增加自己的省电管理导致标准Android行为不一致。这种情况下需要在真机上针对特定型号进行适配和测试。6.3 持续监控与数据记录对于性能测试或功耗分析你可能需要长时间记录电池信息的变化。可以写一个简单的Shell脚本循环抓取数据#!/bin/bash # 文件名battery_logger.sh END_TIME$((SECONDS 60)) # 记录60秒 echo Timestamp,Level(%),Status,Voltage(mV),Temperature(0.1°C) battery_log.csv while [ $SECONDS -lt $END_TIME ]; do TIMESTAMP$(date %Y-%m-%d %H:%M:%S) BATTERY_INFO$(adb shell dumpsys battery) LEVEL$(echo $BATTERY_INFO | grep level | awk {print $2}) STATUS$(echo $BATTERY_INFO | grep status | awk {print $2}) VOLTAGE$(echo $BATTERY_INFO | grep voltage | awk {print $2}) TEMP$(echo $BATTERY_INFO | grep temperature | awk {print $2}) echo $TIMESTAMP,$LEVEL,$STATUS,$VOLTAGE,$TEMP battery_log.csv sleep 2 # 每2秒采样一次 done echo 记录完成。这个脚本会生成一个CSV文件方便你导入到Excel或数据分析工具中绘制电量、电压、温度随时间变化的曲线对于分析App的耗电情况非常有帮助。掌握通过ADB获取和模拟电池信息就像为你的Android开发和测试工作装上了一双“透视眼”和“遥控手”。它让你能更深入地理解设备状态更高效地完成自动化测试。记住核心获取信息是直接而强大的而“设置”信息是一种用于特定测试场景的、临时性的模拟手段。在实际工作中结合模拟器进行复杂场景模拟在真机上主要进行验证是最高效安全的策略。希望这篇详尽的梳理能帮你避开我当年摸索时踩过的那些坑。