在 Android 模拟器中运行 Matter Java 控制器层测试:connectedhomeip 的 Android Emulator Tests 实操指南
2026/9/19 13:41:50 网站建设 项目流程

在 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.ktcluster/ChipClusterStructTest.kt:集群事件结构与数据结构的构造测试
  • src/controller/java/tests/matter/
    • tlv/TlvReaderTest.ktTlvWriterTest.ktTlvReadWriteTest.kt,TLV 读/写/回环测试
    • jsontlv/JsonToTlvToJsonTest.kt:JSON 与 TLV 的互转测试
    • onboardingpayload/ManualCodeTest.ktQRCodeTest.kt,入网配对负载(配对码/二维码)解析测试

这种“镜像包名 + 就近放置”的组织方式,让测试与被测类的调用关系一目了然,也便于在 CI 中按包维度选择要注入的测试库。

二、环境准备:Android SDK、NDK 与工具链版本

docs/platforms/android/android_building.md 给出了明确的版本要求,这也是运行本套测试的环境前提:

1. 版本基线

组件要求版本
Android SDK34
Android NDK28.2.13676358
Gradle Plugin / Gradle8.5.1 / 8.7
JDK17.0
Kotlin(kotlinc 需在$PATH中)2.1.10

2. Android Studio 安装步骤

按官方文档的顺序完成:

  1. 安装 Android Studio;
  2. 安装 NDK:Tools -> SDK Manager -> SDK Tools,勾选 Show Package Details,选择 NDK (Side by Side) 28.2.13676358;
  3. 安装 Command Line Tools(Android SDK Command Line Tools 10.0);
  4. 安装 SDK 平台:Android 14.0 (Upside Down Cake) API Level 34;
  5. 安装模拟器镜像: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.13676358

macOS:

export ANDROID_HOME=~/Library/Android/sdk export ANDROID_NDK_HOME=~/Library/Android/sdk/ndk/28.2.13676358

4. ABI 与 TARGET_CPU 对照表

模拟器/真机的 CPU 架构决定TARGET_CPU的取值:

ABITARGET_CPU
armeabi-v7aarm
arm64-v8aarm64
x86x86
x86_64x64

在 x86_64 的模拟器上通常选用x64;在 arm64 模拟器或真机上选用arm64。选错 ABI 会导致 native 测试库无法加载,JNI 用例直接失败。

5. JDK 与 Kotlin 准备

macOS 可通过 sdkman 安装 JDK 17:

sdk install java 17.0.14-tem

Linux 可直接安装 openjdk-17 并设置JAVA_HOME

sudo apt-get install openjdk-17-jdk export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64

Kotlin 编译器需要 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.sh

2. 构建 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.apk

CHIPTest 工程自身也是一个标准 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.a
  • matterUTestLib:指定要注入的测试静态库。默认值是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); }

它验证两条链路:

  1. 连接成功回调:JNI 侧回调onDeviceConnected,Java 层拿到的devicePointer必须非 0,证明 C++ 设备对象指针经 JNI 正确回传;
  2. 连接失败回调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 的核心约定,完整流程可以归纳为四步:

  1. 按 android_building.md 装好 Android SDK 34、NDK 28.2.13676358、JDK 17、Kotlin 2.1.10,并创建模拟器;
  2. source scripts/bootstrap.sh初始化构建环境(仅首次);
  3. ./scripts/build/build_examples.py --target android-arm64-chip-test build产出 CHIPTest APK 并adb install
  4. 按需在 examples/android/CHIPTest/gradle.properties 调整matterUTestLib(选择被测测试库)与matterBuildSrcDir/matterSdkSourceBuild(源码联调开关),再通过 androidTest 在模拟器上执行。

常见排查点:

  • native 库加载失败 / JNI 用例报错:优先核对模拟器 ABI 与TARGET_CPU是否匹配(x86_64 模拟器应选x64,arm64 选arm64);
  • 想调试 C++ 控制器代码:将matterSdkSourceBuildtrue并让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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询