工厂安全测试(Factory Security)并不是在产线跑一遍杀毒软件,而是围绕Android平台的安全启动链和硬件信任根做一系列确定性校验。产线设备需要保证从Bootloader到系统分区再到应用运行环境,每一层都处于可信状态。如果某个环节被绕过,后续使用时可能出现系统被root、支付环境异常或企业数据泄露等问题。因此,工厂安全测试的每一项结果都应当是可量化、可复现的,不能只凭人工观察。

工厂安全测试的范围与目标
工厂安全测试覆盖启动链、系统完整性、密钥管理和DRM等几个维度。启动链验证主要看Bootloader是否处于锁定状态,以及AVB(Android Verified Boot)对boot、system、vendor等分区的哈希校验是否通过。系统完整性则涉及SELinux是否处于Enforcing模式、dm-verity是否真正启用。密钥管理主要检查Keymaster HAL是否正常,设备是否有硬件级密钥存储,比如StrongBox或TEE。DRM部分常见的是Widevine安全等级,L1表示内容解密在TEE中完成,L3则表示纯软件解密,很多视频应用会限制L3设备的清晰度。
和实验室阶段的安全测试不同,工厂安全测试必须考虑效率与稳定性。产线每台设备停留时间有限,测试项不能依赖网络请求或云端证书验证,因为工厂网络环境可能受限。通常采用离线判断方式,通过读取系统属性、调用系统API或检查证书链来完成。这就要求测试代码轻量、快速,并且能明确返回通过或失败的状态码,方便MES系统记录。
此外,工程模式与用户模式的安全策略可能存在差异。部分ODM设备在工程ROM中会临时解锁Bootloader或关闭SELinux方便调试,但在量产版本中必须恢复。工厂安全测试要能识别当前系统是否为正式用户构建,避免把工程机误判为安全设备,或者把用户机误判为不安全。
核心安全属性读取与验证方法
Android系统在启动过程中会把许多安全状态写入只读系统属性,这是工厂测试最直接的检查入口。常用的属性包括ro.boot.verifiedbootstate,它反映AVB校验结果,正常值应为green;ro.boot.flash.locked表示Bootloader锁定状态,量产设备应为1;ro.boot.vbmeta.device_state显示vbmeta分区的设备状态,locked为正常。此外,ro.build.version.security_patch可以读取安全补丁级别,用于确认系统是否包含最新的漏洞修复。
在产线测试机上,可以直接通过adb命令批量读取这些属性。下面是几个核心命令示例,可以集成到Shell脚本中,或者由测试APK通过Runtime.getRuntime().exec()调用。
# 检查AVB启动状态 adb shell getprop ro.boot.verifiedbootstate # 检查Bootloader锁定状态 adb shell getprop ro.boot.flash.locked # 检查vbmeta设备状态 adb shell getprop ro.boot.vbmeta.device_state # 读取安全补丁级别 adb shell getprop ro.build.version.security_patch # 检查SELinux模式 adb shell getenforce
需要注意的是,getenforce返回Enforcing才表示SELinux策略真正生效。如果返回Permissive,即使系统属性显示AVB为green,也不能判定安全测试通过。因为Permissive模式下大量策略违规只记录不拦截,攻击面会显著扩大。测试脚本应当同时检查SELinux状态,并且与前述属性做联合判断。
工厂测试APK中的自动化检查实现
如果产线没有配备adb环境,更常见的做法是把安全测试集成到一个专用的工厂测试APK中。APK可以调用Android SDK接口读取部分属性,并通过反射读取隐藏属性。以下代码演示了一个SecurityTestUtil类,它检查Bootloader锁定、AVB状态、SELinux模式和Keymaster硬件支持情况。
import android.os.Build;
import android.os.SystemProperties;
import java.lang.reflect.Method;
public class SecurityTestUtil {
public static final int RESULT_PASS = 0;
public static final int RESULT_FAIL_BOOTLOADER = 1;
public static final int RESULT_FAIL_AVB = 2;
public static final int RESULT_FAIL_SELINUX = 3;
public static final int RESULT_FAIL_KEYMASTER = 4;
public static int runAllTests() {
if (!checkBootloaderLocked()) return RESULT_FAIL_BOOTLOADER;
if (!checkAvbState()) return RESULT_FAIL_AVB;
if (!checkSelinuxEnforcing()) return RESULT_FAIL_SELINUX;
if (!checkKeymasterSupport()) return RESULT_FAIL_KEYMASTER;
return RESULT_PASS;
}
private static boolean checkBootloaderLocked() {
String locked = getSystemProperty("ro.boot.flash.locked");
return "1".equals(locked) || "true".equalsIgnoreCase(locked);
}
private static boolean checkAvbState() {
String state = getSystemProperty("ro.boot.verifiedbootstate");
String deviceState = getSystemProperty("ro.boot.vbmeta.device_state");
return "green".equals(state) && "locked".equals(deviceState);
}
private static boolean checkSelinuxEnforcing() {
String enforcing = getSystemProperty("ro.build.selinux");
if ("1".equals(enforcing)) return true;
try {
Class<?> c = Class.forName("android.os.SELinux");
Method m = c.getMethod("isSELinuxEnforced");
return (Boolean) m.invoke(null);
} catch (Exception e) {
return false;
}
}
private static boolean checkKeymasterSupport() {
// 检查Keymaster HAL版本,实际项目可通过KeyChain或Keystore接口验证
String km = getSystemProperty("ro.hardware.keystore");
return km != null && !km.isEmpty();
}
private static String getSystemProperty(String key) {
try {
Class<?> sp = Class.forName("android.os.SystemProperties");
Method get = sp.getMethod("get", String.class);
return (String) get.invoke(null, key);
} catch (Exception e) {
return null;
}
}
}
这段代码中checkSelinuxEnforcing优先读取ro.build.selinux属性,如果不可用则通过反射调用android.os.SELinux.isSELinuxEnforced()。需要注意的是,Android 8.0之后部分系统属性对普通应用不可见,测试APK需要签名成系统应用或使用android:sharedUserId="android.uid.system",并且运行在系统进程。否则SystemProperties.get可能返回空值。此外,Keymaster检查只是简单判断属性是否存在,实际工厂测试中应通过KeyStore.getInstance("AndroidKeyStore")生成密钥并验证其是否存储在TEE中,这需要额外的证书链解析和Attestation验证。
常见失败场景与排查建议
工厂安全测试失败时,产线人员往往会直接判定主板问题,但实际上多数失败与软件配置相关。最常见的是Bootloader锁定状态为0。这通常是因为烧录的工程版本带有解锁标志,或者前一个工位执行了fastboot oem unlock。此时需要检查版本包是否为量产签名版本,以及烧录后是否执行了锁定命令fastboot oem lock或fastboot flashing lock。
另一种高频失败是AVB状态为yellow或orange。yellow表示使用了非官方的签名密钥,比如开发阶段的自签名vbmeta;orange则说明设备允许解锁启动,通常与Bootloader锁定状态有关。遇到这种情况,要核对vbmeta.img是否由原厂的release key签名,并且boot.img、system.img的哈希是否包含在vbmeta的校验描述中。如果修改了系统分区但未重新生成vbmeta,也会导致校验失败。
Widevine等级异常也是工厂测试中容易漏掉的问题。有些设备在工厂测试APK中只检查了getprop ro.boot.verifiedbootstate,却没有验证DRM信息。实际上,即使启动链正常,如果TEE中的Widevine keybox未写入或过期,DRM等级会降为L3。此时可以通过dumpsys media.drm命令查看Widevine安全等级,若为L3则需要检查keybox烧录工位是否成功,以及设备时间是否同步。DRM证书验证依赖时间戳,如果产线设备时间错误,也可能导致判定失败。
排查时建议开启adb logcat -s keystore avb libc抓取相关日志,同时记录每次测试时的属性快照。通过对比通过设备和失败设备的属性值,可以快速缩小问题范围。工厂测试代码中应当输出完整的失败码和属性值,而不是只返回一个布尔值,这样便于MES系统追溯。

