在 Android 模拟器中运行 Matter Java 控制器层测试:connectedhomeip 的 Android Emulator Tests 实操指南
【免费下载链接】connectedhomeipMatter (formerly Project CHIP) creates more connections between more objects, simplifying development for manufacturers and increasing compatibility for consumers, guided by the Connectivity Standards Alliance.项目地址: https://gitcode.com/GitHub_Trending/co/connectedhomeip
本文以 src/controller/java/tests/README.md 为骨架,讲解 Matter(原 Project CHIP,connectedhomeip 仓库)Android 控制器层单元测试的运行方式:为什么这些测试“必须在外部运行”、如何搭建 Android SDK/NDK 环境、如何用构建脚本产出 CHIPTest 测试应用、如何通过gradle.properties切换被测测试库,并结合测试源码剖析 JNI 回调测试与 TLV 编解码测试各自依赖什么运行环境。读完本文,你能够独立完成一套“从源码编译 → 模拟器安装 → 运行控制器层单测”的完整流程。
一、文档核心约定:这些测试必须在外部运行
README.md 的内容虽然简短,但它确立了一个关键约束:
These tests must be run externally
构建与模拟器配置,请参见 Building Android 指南。
结合仓库结构,可以这样理解这句话:src/controller/java/下的 Java/Kotlin 控制器代码(设备控制器、TLV 编解码、JSON-TLV 转换、Onboarding Payload 解析等)并不是一个独立的 Android 工程,它编译后以测试库的形式被注入到examples/android/CHIPTest这个 Android 测试应用中。因此,测试无法像 JVM 下的纯单元测试那样在裸主机上直接gradlew test完成全部验证——涉及 JNI 的测试用例需要真实加载 native 库,必须借助 Android 模拟器或真机外部执行。
测试目录结构:被测代码与测试用例的对应关系
src/controller/java/tests/目录按被测包名镜像组织,当前包含两组测试:
src/controller/java/tests/chip/devicecontroller/- GetConnectedDeviceCallbackJniTest.java:验证设备连接回调的 JNI 桥接
cluster/ChipClusterEventStructTest.kt、cluster/ChipClusterStructTest.kt:集群事件结构与数据结构的构造测试
src/controller/java/tests/matter/tlv/:TlvReaderTest.kt、TlvWriterTest.kt、TlvReadWriteTest.kt,TLV 读/写/回环测试jsontlv/JsonToTlvToJsonTest.kt:JSON 与 TLV 的互转测试onboardingpayload/:ManualCodeTest.kt、QRCodeTest.kt,入网配对负载(配对码/二维码)解析测试
这种“镜像包名 + 就近放置”的组织方式,让测试与被测类的调用关系一目了然,也便于在 CI 中按包维度选择要注入的测试库。
二、环境准备:Android SDK、NDK 与工具链版本
docs/platforms/android/android_building.md 给出了明确的版本要求,这也是运行本套测试的环境前提:
1. 版本基线
| 组件 | 要求版本 |
|---|---|
| Android SDK | 34 |
| Android NDK | 28.2.13676358 |
| Gradle Plugin / Gradle | 8.5.1 / 8.7 |
| JDK | 17.0 |
Kotlin(kotlinc 需在$PATH中) | 2.1.10 |
2. Android Studio 安装步骤
按官方文档的顺序完成:
- 安装 Android Studio;
- 安装 NDK:Tools -> SDK Manager -> SDK Tools,勾选 Show Package Details,选择 NDK (Side by Side) 28.2.13676358;
- 安装 Command Line Tools(Android SDK Command Line Tools 10.0);
- 安装 SDK 平台:Android 14.0 (Upside Down Cake) API Level 34;
- 安装模拟器镜像:Tools -> Device Manager -> Create device -> Pixel 5 -> Android S API 34。
3. 环境变量设置
Linux:
export ANDROID_HOME=~/Android/Sdk export ANDROID_NDK_HOME=~/Android/Sdk/ndk/28.2.13676358macOS:
export ANDROID_HOME=~/Library/Android/sdk export ANDROID_NDK_HOME=~/Library/Android/sdk/ndk/28.2.136763584. ABI 与 TARGET_CPU 对照表
模拟器/真机的 CPU 架构决定TARGET_CPU的取值:
| ABI | TARGET_CPU |
|---|---|
| armeabi-v7a | arm |
| arm64-v8a | arm64 |
| x86 | x86 |
| x86_64 | x64 |
在 x86_64 的模拟器上通常选用x64;在 arm64 模拟器或真机上选用arm64。选错 ABI 会导致 native 测试库无法加载,JNI 用例直接失败。
5. JDK 与 Kotlin 准备
macOS 可通过 sdkman 安装 JDK 17:
sdk install java 17.0.14-temLinux 可直接安装 openjdk-17 并设置JAVA_HOME:
sudo apt-get install openjdk-17-jdk export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64Kotlin 编译器需要 2.1.10,Linux 下把 kotlinc 下载解压到/usr/lib后加入$PATH即可;macOS 可用sdk install kotlin 2.1.10。
三、构建 CHIPTest:从源码产出测试 APK
Android 侧有两个相关应用:CHIPTool(配网与控制工具)和 CHIPTest(运行 Matter 单元测试)。本主题只关心后者,且 CHIPTest目前只能通过构建脚本编译,无法在 Android Studio 中直接构建。
1. 初始化构建环境
# 检出仓库后,首次需要执行 source scripts/bootstrap.sh2. 构建 CHIPTest 测试包
在仓库根目录执行:
./scripts/build/build_examples.py --target android-arm64-chip-test build该命令会先编译 Matter C++ 核心与 Java 控制器层,再经 Gradle 打包出app-debug.apk。产物位于out/android-<TARGET_CPU>-chip-test/outputs/apk/debug/,可通过 adb 安装到模拟器:
adb install out/android-$TARGET_CPU-chip-test/outputs/apk/debug/app-debug.apkCHIPTest 工程自身也是一个标准 Gradle 工程(examples/android/CHIPTest/gradlew),其app/src/androidTest/目录存放运行在设备端(androidTest)的测试入口,这正是“测试必须在外部(模拟器/真机)运行”的落点:androidTest 由adb触发在设备进程内执行,能加载jniLibs中的 native 库。
3. 切换被测测试库:matterUTestLib
examples/android/CHIPTest/gradle.properties 中有三个与本文主题直接相关的开关:
# Build SDK from source code and debug in Android Studio. Must also set matterBuildSrcDir. matterSdkSourceBuild=false # Point to the SDK build dir (out/android-arm64-chip-test for example) # to build SDK from source code and debug in Android Studio. # Set to blank to use the SDK prebuilt by scripts/build/build_examples.py. matterBuildSrcDir=out/android-arm64-chip-test # Test libs to run matterUTestLib=libPlatformTests.amatterUTestLib:指定要注入的测试静态库。默认值是libPlatformTests.a(平台层测试),要改跑控制器层测试时,将其指向src/controller/java/对应的测试库产物即可——这就是 README 中“run these tests externally”的具体含义:先由 GN 构建出测试库,再由 CHIPTest 的 Gradle 工程在模拟器上执行;matterBuildSrcDir/matterSdkSourceBuild:从源码构建并在 Android Studio 中调试 SDK 时,指向out/android-arm64-chip-test一类的输出目录,并将matterSdkSourceBuild置为true;留空则使用build_examples.py预构建产物。
4. 运行测试
APK 安装后,可通过 adb 触发 androidTest(以设备端测试为例):
adb shell am instrument -w <测试包名>.test或在 Android Studio 的 Device Explorer / Run 菜单中选择 androidTest 源码集运行;-e class参数可以精确到某个测试类,例如只跑 TLV 读取测试。
四、测试源码剖析:哪些用例真正依赖模拟器
从 GetConnectedDeviceCallbackJniTest.java 可以看清“外部运行”的必要性。该测试类使用@RunWith(AndroidJUnit4.class),即 instrumented test,依赖真实的 Android 运行时与 JNI:
@Before public void setUp() { callbackTestUtil = new GetConnectedDeviceCallbackForTestJni(new MessagingContext()); } @Test public void deviceConnected() { var callback = new FakeGetConnectedDeviceCallback(); var jniCallback = new GetConnectedDeviceCallbackJni(callback); callbackTestUtil.onDeviceConnected(jniCallback); assertThat(callback.devicePointer).isNotEqualTo(0L); }它验证两条链路:
- 连接成功回调:JNI 侧回调
onDeviceConnected,Java 层拿到的devicePointer必须非 0,证明 C++ 设备对象指针经 JNI 正确回传; - 连接失败回调:
onDeviceConnectionFailure(jniCallback, 100L)后,Java 层应收到ChipDeviceControllerException,且errorCode == 100L,验证错误码跨层传递的保真性。
这类测试无法在纯 JVM 中完成,因为MessagingContext与 JNI 方法需要加载libCHIP...系列 native 库,这正是必须在模拟器/真机上执行的原因。
相对地,纯 Kotlin 的 TLV 测试则不依赖 native 库。以 TlvReaderTest.kt 为例,它使用标准@RunWith(JUnit4::class),并内嵌了一段真实配对流程中提取的 Fabric 配置 TLV 十六进制数据作为回归样本:
// Extracted from a Newman device during a pairing flow. Represents a fabric // ID and keys for the fabric 7885a14c693bf1cb. private val fabricConfig = """ D50000050001002701CBF13B694CA18578360 21525010110240201300310149BF1430B26F5 ... """.trimIndent().replace("\n", "") .chunked(2).map { it.toInt(16) and 0xFF }.map { it.toByte() }.toByteArray()测试断言TlvReader能依次解析出 Structure 类型首元素、Fabric ID(0x7885a14c693bf1cb,以ContextSpecificTag1 携带的UnsignedIntValue形式出现)、证书数组(AnonymousTag+ArrayValue)以及厂商 ID(0x1001)。这种“从真实设备抓取的 TLV 样本”保证了 TLV 编解码器对线上数据的兼容性回归,属于控制器层数据面质量的关键防线。
综合来看,src/controller/java/tests/是两类用例的集合:JNI 桥接类用例(chip.devicecontroller.*)必须在外部设备环境运行;TLV/JSON/OnboardingPayload 类用例(matter.*)本身是纯 JVM 逻辑,但也统一经由 CHIPTest 的 androidTest 通道在模拟器上执行,从而与整包构建流程保持一致。
五、小结与常见排查点
围绕 src/controller/java/tests/README.md 的核心约定,完整流程可以归纳为四步:
- 按 android_building.md 装好 Android SDK 34、NDK 28.2.13676358、JDK 17、Kotlin 2.1.10,并创建模拟器;
source scripts/bootstrap.sh初始化构建环境(仅首次);./scripts/build/build_examples.py --target android-arm64-chip-test build产出 CHIPTest APK 并adb install;- 按需在 examples/android/CHIPTest/gradle.properties 调整
matterUTestLib(选择被测测试库)与matterBuildSrcDir/matterSdkSourceBuild(源码联调开关),再通过 androidTest 在模拟器上执行。
常见排查点:
- native 库加载失败 / JNI 用例报错:优先核对模拟器 ABI 与
TARGET_CPU是否匹配(x86_64 模拟器应选x64,arm64 选arm64); - 想调试 C++ 控制器代码:将
matterSdkSourceBuild置true并让matterBuildSrcDir指向实际输出目录(如out/android-arm64-chip-test),即可在 Android Studio 中从源码构建; - 只想跑控制器层测试而非平台层:把
matterUTestLib从默认的libPlatformTests.a改为对应的测试库产物名。
这套机制把 Matter 的 GN 构建体系与 Android instrumented test 体系桥接在一起:GN 负责产出可注入的测试静态库,CHIPTest 负责在模拟器/真机上执行,从而让src/controller/java/控制器层在每次改动后都能得到与真实设备一致的验证。
【免费下载链接】connectedhomeipMatter (formerly Project CHIP) creates more connections between more objects, simplifying development for manufacturers and increasing compatibility for consumers, guided by the Connectivity Standards Alliance.项目地址: https://gitcode.com/GitHub_Trending/co/connectedhomeip
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考