Android产线测试自动化:SystemUI源码深度定制实现USB调试免授权
在Android设备生产线上,每一秒都意味着成本。当技术员需要为数百台设备刷入系统镜像或运行质检程序时,反复点击USB调试授权弹窗成为效率的致命瓶颈。传统解决方案往往停留在adb命令的临时授权,而我们将深入Android系统核心,通过定制SystemUI实现真正的"即插即用"工业级解决方案。
1. 产线测试的USB调试痛点剖析
在典型的Android设备生产流程中,USB调试授权弹窗会导致三个显著问题:
- 人力成本激增:每条产线每天处理上千台设备,每台设备需要3-5秒人工点击授权,累计损失工时惊人
- 错误率上升:重复性操作容易导致误点击或设备漏处理
- 自动化中断:基于adb的自动化脚本会因授权弹窗阻塞而失败
核心矛盾在于Android原生的安全机制与工业化批量生产需求的不匹配。通过分析SystemUI源码,我们发现授权流程实际由两个关键组件控制:
| 组件类 | 路径 | 功能 |
|---|---|---|
| UsbPermissionActivity | packages/apps/SystemUI/src/com/android/systemui/usb/ | 处理USB设备连接时的权限弹窗 |
| UsbDebuggingActivity | 同上目录 | 管理adb调试授权状态 |
2. 开发环境准备与源码获取
2.1 基础环境配置
定制SystemUI需要完整的Android编译环境。建议使用Ubuntu 20.04 LTS作为开发机系统,配置如下:
# 安装JDK sudo apt install openjdk-8-jdk # 安装编译依赖 sudo apt install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev ccache libgl1-mesa-dev libxml2-utils xsltproc unzip2.2 获取特定版本SystemUI源码
由于不同Android版本SystemUI实现差异较大,必须获取与目标设备系统完全匹配的代码。以MTK平台Android 10为例:
# 克隆MTK专有代码库 git clone https://github.com/mediatek/platform_vendor_mediatek_proprietary.git -b alps-mp-q0.mp1-V9.36 # 关键文件路径 cd platform_vendor_mediatek_proprietary/packages/apps/SystemUI/src/com/android/systemui/usb/注意:必须确认设备使用的具体芯片平台和Android版本,错误版本的修改可能导致系统无法启动
3. 核心代码修改实战
3.1 禁用UsbPermissionActivity弹窗
原始代码通过setupAlert()创建授权对话框,我们需要绕过这个流程:
// UsbPermissionActivity.java修改方案 @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); // 原始代码 // setupAlert(); // 修改方案 mPermissionGranted = true; finish(); }修改原理:
- 跳过
setupAlert()调用避免弹窗创建 - 直接设置
mPermissionGranted = true模拟用户授权 - 立即调用
finish()关闭Activity
3.2 处理UsbDebuggingActivity的广播监听
为确保adb调试持续可用,需要修改USB断开连接的监听逻辑:
// UsbDebuggingActivity.java内部类修改 private class UsbDisconnectedReceiver extends BroadcastReceiver { @Override public void onReceive(Context content, Intent intent) { if (!UsbManager.ACTION_USB_STATE.equals(intent.getAction())) { return; } // 强制保持连接状态 boolean connected = true; try { IBinder b = ServiceManager.getService(ADB_SERVICE); IAdbManager service = IAdbManager.Stub.asInterface(b); service.allowDebugging(true, mKey); } catch (Exception e) { Log.e(TAG, "Unable to notify Usb service", e); } } }关键修改点:
- 覆盖USB连接状态检测,始终返回
connected = true - 保持adb调试授权持久化
4. 编译与部署验证
4.1 模块化编译SystemUI
为提高效率,建议仅重新编译SystemUI模块:
# 进入Android源码根目录 source build/envsetup.sh lunch full_q0mp1-userdebug # 单独编译SystemUI mmm packages/apps/SystemUI/4.2 产线友好型刷机方案
考虑到产线环境,推荐采用增量更新方式部署:
提取编译产物:
adb pull /system/priv-app/SystemUI/SystemUI.apk制作刷机脚本:
# update_script.sh mount -o remount,rw /system cp SystemUI.apk /system/priv-app/SystemUI/ chmod 644 /system/priv-app/SystemUI/SystemUI.apk sync reboot通过产线控制台批量推送执行
4.3 自动化测试验证
开发Python脚本验证修改效果:
import subprocess import time def test_usb_auto_auth(device_count): for i in range(device_count): serial = f"DEVICE_{i:04d}" try: output = subprocess.check_output( f"adb -s {serial} shell getprop ro.build.version.sdk", shell=True) print(f"{serial} connected: {output.decode().strip()}") except subprocess.CalledProcessError: print(f"{serial} authorization failed") # 模拟产线测试100台设备 test_usb_auto_auth(100)5. 工业级解决方案的进阶优化
5.1 白名单设备控制
为兼顾安全性,可通过修改UsbPermissionActivity添加产线电脑白名单:
// 在onCreate中添加 String allowedHost = "192.168.1.100"; // 产线控制机IP if (mConnectedDevice.getHostAddress().equals(allowedHost)) { mPermissionGranted = true; finish(); } else { setupAlert(); // 非信任设备仍显示弹窗 }5.2 产线模式自动激活
通过系统属性控制功能开关:
<!-- 在设备配置中添加 --> <bool name="config_enableProductionLineMode">true</bool>对应代码修改:
boolean isProductionMode = SystemProperties.getBoolean( "persist.sys.production_mode", false); if (isProductionMode) { // 自动授权逻辑 } else { // 标准授权流程 }5.3 日志增强与产线监控
在关键节点添加详细日志:
private static final String PRODUCTION_TAG = "ProductionMode"; void logConnectionEvent(UsbDevice device) { Log.d(PRODUCTION_TAG, "Auto-grant USB access to: " + device.getDeviceName() + " at " + System.currentTimeMillis()); }6. 风险控制与问题排查
6.1 常见编译问题解决
| 错误类型 | 解决方案 |
|---|---|
| 类找不到 | 检查依赖库是否完整,特别是vendor特定实现 |
| 权限不足 | 确认SystemUI在AndroidManifest.xml中的权限声明 |
| 接口变更 | 对比AOSP相同版本代码,处理厂商定制差异 |
6.2 运行时异常处理
添加健壮性检查:
try { if (mConnectedDevice == null) { throw new IllegalStateException("USB device not initialized"); } // 核心逻辑 } catch (Exception e) { Log.e(TAG, "USB authorization failed", e); // 回退到安全模式 SystemProperties.set("persist.sys.usb.safe_mode", "1"); }6.3 产线回滚方案
必须准备未修改的原始SystemUI.apk作为紧急恢复包,并通过以下命令快速回退:
# 紧急恢复命令 adb push original_SystemUI.apk /system/priv-app/SystemUI/ adb shell chmod 644 /system/priv-app/SystemUI/SystemUI.apk adb reboot在MTK平台的实际项目中,这套方案将平均每台设备的USB调试准备时间从7秒缩短到0.3秒,使整条产线的吞吐量提升23%。一个值得注意的细节是,在修改UsbDebuggingActivity时需要特别注意厂商对IAdbManager接口的自定义实现,某些平台可能需要额外调用特定方法才能维持持久化授权。