히스토리

  • [2026-03-11 Wed 11:15] @pi-claude — 문서 리팩터링: RK3576 한정 → Android arm64 범용 가이드로 확장. NDK 빌드 7개 이슈 테이블 추가. 재현 가능 빌드 스크립트(build-otbr.sh) 반영
  • [2026-03-11 Wed 10:55] @pi-claude — NDK 빌드 성공! 6번 시도, 7개 이슈 해결. otbr-agent 6.9MB + ot-ctl 12KB (arm64 stripped). dist/otbr-arm64/에 복사
  • [2026-03-10 Tue 18:03] @junghan — 다른 작업하느라 내가 정신 없었음에도 멋지게 작업을 해주는 여러분께 감사!
  • [2026-03-10 Tue 17:52] @pi-claude — Go ot-ctl 경로 환경변수, rk3576-thread.sh, docs/THREAD.md, NDK r28c 제거, connectedhomeip 28GB 삭제. NDK 빌드 tmux 진행 중 (SKS 네트워크 느림→집에서 이어갈 것)
  • [2026-03-10 Tue 14:01] 생성 — RPi5 Thread 스택 검증 후 Android 이식 계획 수립. bd-277.1 작업 가이드.

왜 Android arm64인가 — Yocto Linux 유일한 선택지가 아닌 이유

HomeAgent의 Thread Border Router(OTBR)는 원래 RPi5(Yocto Linux) 전용이었다. 그러나 smart home hub 시장의 현실은 다르다:

  • 안드로이드 SBC 시장이 더 크다. RK3576, RK3588, Amlogic S905X4, MT8395 등 — Android 탑재 보드가 가격/성능/가용성에서 RPi5보다 유리한 경우가 많다.
  • Thread RCP가 UART로 연결되면 OS 독립적이다. ESP32-H2든 Silicon Labs EFR32든, Spinel HDLC over UART는 Linux/Android 공통이다.
  • ot-br-posix는 POSIX 코드다. Android도 POSIX 호환. NDK로 빌드하면 돌아간다.
  • 고객 프로젝트에서 Android 보드가 주어진다. K 프로젝트의 RK3576이 계기였지만, 패턴은 반복된다.

따라서 이 문서는 *특정 보드가 아닌 “Android arm64에서 OTBR 돌리기” 범용 가이드*다. 검증 보드가 RK3576일 뿐, 다른 Android arm64 보드에서도 동일하게 적용된다.

적용 가능한 보드 (요구사항)

요구사항이유
Android arm64 (API 30+)NDK 빌드 타겟
UART 접근 가능Thread RCP 연결
adb root 또는 userdebugSELinux, /dev 접근
TUN 커널 모듈wpan0 인터페이스
WiFi 또는 이더넷backbone 인터페이스

검증 보드:

  • RK3576-EVB (Android 15, ESP32-H2 UART5) — 이 문서의 주요 검증 대상
  • 이론적 호환: RK3588 Android, MT8395 Android, 기타 arm64-v8a userdebug 보드

RPi5 검증 완료 스택 (2026-03-10 실증) — 기준선

이식의 기준이 되는 RPi5 Yocto 스택:

ESP32-H2 (ZBDongle-E, /dev/ttyUSB0, 460800baud)
  └─ otbr-agent -I wpan0 -B eth0 spinel+hdlc+uart:///dev/ttyUSB0?uart-baudrate=460800
       ├─ Thread: leader, ch=26, panid=0xe8e9, network=OpenThread-e8e9
       ├─ SRP server: running
       └─ wpan0: UP, IPv6 (fd88:1bc0:d9c2:...)
            └─ matterjs :5580 (fabric=1, ble=true, thread=true)
                 └─ Go homeagent :8080
                      └─ A2UI 웹 대시보드
 
Thread 디바이스 (Tuya DS001-T, sleepy end device, battery):
  - node 1: 현관문 센서 (contact_sensor) — 여닫기 실시간 확인 ✅
  - node 7: 화장실 센서 (contact_sensor) — 동작 확인 ✅
  - LLM 에이전트: "현관문이 닫혔습니다" (Gemini Flash)

Yocto Linux vs Android — 플랫폼 분기점

같은 ot-br-posix 소스, 같은 역할. 빌드와 배포만 다르다.

항목RPi5 (Yocto Linux)Android arm64비고
소스ot-br-posixot-br-posix✅ 동일
빌드bitbake (OE toolchain)NDK r27 (cmake)툴체인만 다름
mDNSavahi-daemonOT core (내장)Android에 avahi 없음
initsystemdshell scriptAndroid에 systemd 없음
RCP/dev/ttyUSB0 (USB)/dev/ttyS5 (UART)보드 의존
backboneeth0wlan0보드 의존
baudrate460800460800✅ 동일
SRP serverotbr-agent 내장otbr-agent 내장✅ 동일
Go 연동ot-ctl → hub.goot-ctl → hub.go✅ 동일

핵심: 프로토콜 계층(Spinel, Thread, SRP, matterjs)은 동일. 인프라 계층(init, mDNS, 권한)만 다르다.

NDK 크로스빌드 — 검증 완료 (2026-03-11)

소스 버전 고정

소스커밋비고
ot-br-posixc19319c7~/repos/3rd/ot-br-posix
openthread (submodule)0887643bfthird_party/openthread/repo
NDKr27 (27.0.12077973)nix devShell, flake.nix

빌드 명령

재현 가능 빌드 스크립트: homeagent-config/scripts/build-otbr.sh

# nix devShell 진입 후 실행
cd ~/repos/gh/homeagent-config
./run.sh otbr-build
 
# 또는 직접
nix develop .#dev --impure --command bash scripts/build-otbr.sh

핵심 CMake 옵션:

cmake -B build-android \
  -DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
  -DANDROID_ABI=arm64-v8a \
  -DANDROID_PLATFORM=android-35 \
  -DANDROID_STL=c++_static \
  -DCMAKE_CXX_FLAGS="-DOPENTHREAD_CONFIG_ANDROID_NDK_ENABLE=1" \
  -DCMAKE_C_FLAGS="-DOPENTHREAD_CONFIG_ANDROID_NDK_ENABLE=1" \
  -DOT_ANDROID_NDK=ON \
  -DBUILD_TESTING=OFF \
  -DOTBR_DBUS=OFF -DOTBR_REST=OFF -DOTBR_WEB=OFF \
  -DOTBR_MDNS=openthread \
  -DOTBR_BACKBONE_ROUTER=OFF \
  -DOTBR_SRP_ADVERTISING_PROXY=OFF \
  -DOTBR_BORDER_ROUTING=ON \
  -DOTBR_BORDER_AGENT=ON \
  -DOT_SPINEL_RESET_CONNECTION=ON \
  -DOT_TREL=OFF -DOT_MLR=ON \
  -DOT_SRP_SERVER=ON -DOT_ECDSA=ON -DOT_SERVICE=ON \
  -DOT_DUA=ON -DOT_BORDER_ROUTING_NAT64=OFF \
  -DOTBR_INFRA_IF_NAME=wlan0 \
  -DOTBR_NO_AUTO_ATTACH=1

7개 이슈와 해결 (빌드 6번 시도)

#이슈원인해결
1cutils/properties.h not foundAndroid NDK에 없는 system 헤더-DOPENTHREAD_CONFIG_ANDROID_NDK_ENABLE=1
2Only one Discovery ProxyOT_DISCOVERY_PROXY(기본ON) + DNSSD 충돌DNSSD_DISCOVERY_PROXY 제거
3Only one Advertising ProxyMDNS=openthread에서 OT_SRP_ADV_PROXY 자동ONSRP_ADVERTISING_PROXY=OFF
4-lutil not foundglibc 전용 라이브러리, Android에 없음-DOT_ANDROID_NDK=ON
5sign-compare fatal errorNDK clang -Werrorudp.cpp static_cast<unsigned int> 패치
6libnetfilter_queue.h not foundAndroid에 없는 Linux 헤더BACKBONE_ROUTER=OFF
7dns_sd.h not foundmDNSResponder 미포함MDNS=openthread (OT core mDNS)

패치 파일: homeagent-config/patches/ot-br-posix/0001-fix-udp-sign-compare-ndk-clang.patch 빌드 스크립트가 자동 적용.

산출물

바이너리크기 (stripped)아키텍처
otbr-agent6.9MBELF arm64, /system/bin/linker64
ot-ctl12KBELF arm64, /system/bin/linker64

Yocto 빌드와의 핵심 차이

CMake 옵션YoctoAndroid NDK왜 다른가
OTBR_DBUSONOFFAndroid에 dbus 없음
OTBR_MDNSavahiopenthreadAndroid에 avahi 없음
OTBR_BACKBONE_ROUTERONOFFlibnetfilter_queue 불가
OT_ANDROID_NDK(없음)ON-lutil 제외
ANDROID_NDK_ENABLE(없음)1cutils → sys/system_properties
OT_TRELONOFFDNS-SD 기반, 외부 mDNS 없이 불가

Android 보드 데이터 수집 (RK3576 기준)

특정 보드에서 실행하기 전에 수집해야 할 데이터. 다른 Android 보드에도 동일한 체크리스트.

필수 확인 항목

# 1. 아키텍처
adb shell getprop ro.product.cpu.abi          # arm64-v8a
adb shell getprop ro.build.version.sdk        # API level (30+)
 
# 2. Thread RCP UART
adb shell ls -la /dev/ttyS* /dev/ttyUSB*      # UART 디바이스
adb shell cat /proc/tty/driver/serial          # UART 상세
 
# 3. TUN 지원
adb shell zcat /proc/config.gz | grep CONFIG_TUN  # =y or =m
adb shell ls -la /dev/tun /dev/net/tun
 
# 4. SELinux
adb shell getenforce                           # Enforcing/Permissive
adb shell ls -Z /dev/ttyS5                     # UART의 SELinux 컨텍스트
 
# 5. 기존 Thread HAL (있으면 중지 필요)
adb shell pm list packages | grep thread
adb shell ps -A | grep -E "ot-daemon|threadnetwork"
 
# 6. IPv6
adb shell sysctl net.ipv6.conf.all.forwarding
adb shell ip -6 addr show
 
# 7. 네트워크 인터페이스
adb shell ip link show                         # wlan0/eth0 확인

RK3576 수집 결과 (2026-03-10)

항목
SoCRK3576 (Cortex-A72 + A53)
Android15 (API 35)
Kernel6.1.118 aarch64
ABIarm64-v8a
SELinuxEnforcing (setenforce 0 가능, userdebug)
WiFiSKS&GQ_TEST_2.4 (192.168.69.5)
ESP32-H2/dev/ttyS5 (UART5, 460800)
TUNCONFIG_TUN=y, /dev/tun 존재
Thread HALcom.android.hardware.threadnetwork (PID 598)
ot-daemonstopped
/system/bin/ot-ctl존재 (ot-daemon 전용, otbr-agent과 호환 안됨)

배포 및 실행 (RK3576 기준)

배포

./run.sh otbr-deploy   # adb push otbr-agent + ot-ctl

Thread 시작

./run.sh rk-thread-start   # HAL 중지 → SELinux → TUN → otbr-agent → dataset → SRP

상세: scripts/rk3576-thread.sh (start/stop/status)

전체 스택 시작 순서

1. stop vendor.threadnetwork_hal / ot-daemon
2. setenforce 0
3. ip tuntap add wpan0
4. sysctl IPv6 forwarding
5. otbr-agent (wpan0 + /dev/ttyS5 + wlan0)
6. ot-ctl: dataset init/commit, ifconfig up, thread start
7. ot-ctl: srp server enable
8. matterjs-server :5580
9. Go homeagent :8080 (getOTBRDataset → set_thread_dataset 자동)
10. Flutter APK (WebView localhost:8080)

리스크 및 미검증 사항

#리스크심각도상태
1MDNS=openthread 기능 제약빌드 성공, 실동작 미검증
2BACKBONE_ROUTER=OFF로 인한 IPv6 라우팅 제한실 Thread 디바이스 테스트 필요
3Android netd와 wpan0 TUN 충돌RK3576에서 실행 시 확인
4/dev/ttyS5 baudrate (460800 vs 115200)HAL rc 기준 460800, RCP 로그 115200. auto-baud 의심
5ot-ctl 소켓 경로otbr-agent의 UNIX socket 위치 확인 필요
6SELinux re-enable 시 otbr-agent 차단sepolicy 패치 필요할 수 있음

K 프로젝트 참고 사항

K 프로젝트에서 같은 RK3576에서 Thread 검증한 경험:

항목
NDK28.2.13676358 (homeagent은 27 사용)
Thread HALAndroid 기본 HAL + ot-daemon 방식
커미셔닝CHIPTool (우리는 matterjs 사용)
Thread 성공Nanoleaf Thread 전구 커미셔닝 완료
핵심 차이HAL 경유 vs POSIX 직접 — 완전히 다른 경로

homeagent은 HAL을 우회하고 ot-br-posix를 직접 실행한다. 이유: matterjs-server와의 통합 (ot-ctl → set_thread_dataset), 재현 가능한 빌드.

관련 문서