Android 기기 또는 Thread 칩 공급업체가 아닌 경우 지금 바로 읽기를 중단하셔도 됩니다.
이 문서에서는 최신 AOSP 소스 코드로 새로운 Android 기반 Thread Border Router 기기를 빌드하는 단계를 안내합니다. 이 문서를 따르면 다음을 알아볼 수 있습니다.
지원이 필요한 경우 GitHub에서 문제를 신고하거나 질문이 있는 경우 토론을 시작하세요.
개요
Android 스레드 스택은 Google에서 GitHub에 오픈소스로 제공하는 OpenThread 및 ot-br-posix
를 기반으로 합니다. OpenThread가 공개 GitHub 저장소에서 개발되는 것과 마찬가지로 Android 스레드 스택은 공개 AOSP 코드베이스에서 개발됩니다. 모든 기능과 버그 수정은 먼저 AOSP에 제출됩니다. 이를 통해 공급업체는 정규 Android 출시를 기다리지 않고도 최신 스레드 버전을 도입할 수 있습니다.
아키텍처
전체 Android 스레드 스택은 두 가지 주요 구성요소로 구성됩니다. 일반 시스템 파티션의 핵심 스레드 스택과 공급업체 파티션의 스레드 HAL 서비스입니다. 기기 공급업체는 일반적으로 HAL 서비스를 관리하고 빌드하기만 하면 됩니다.
다음은 Android 스레드 스택의 작동 방식을 간략하게 요약한 내용입니다.
- 시스템 서버에는 전체 스택을 관리하는 Java 스레드 시스템 서비스가 있습니다. 이 서비스는 스레드 시스템 API를 제공하고, thread-wpan
터널 인터페이스를 만들고, 스레드 네트워크를 연결 서비스에 등록하고, 경계 라우팅 및 광고 프록시 기능을 구현합니다.
- 핵심 스레드 / OpenThread 스택은 권한이 없는 독립형 네이티브 프로세스(이름: ot-daemon
)에서 호스팅됩니다. ot-daemon
는 비공개 AIDL API를 통해 Java 시스템 서비스에서 직접 관리되며 Thread HAL API를 통해 스레드 하드웨어 라디오에 액세스합니다.
- 공급업체 제공 Thread HAL 서비스는 Thread HAL API를 구현해야 합니다(MUST). 일반적으로 RCP로 작동하며 스피넬 프로토콜을 구현합니다.
코드는 어디에 있나요?
- Android 스레드 프레임워크 / API 및 서비스: https://cs.android.com/android/platform/superproject/main/+/main:packages/modules/Connectivity/thread/
- Thread HAL API 및 기본 서비스 구현: https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/threadnetwork/
- 가져온 OpenThread 저장소: https://cs.android.com/android/platform/superproject/main/+/main:external/openthread/
- 가져온 ot-br-posix 저장소: https://cs.android.com/android/platform/superproject/main/+/main:external/ot-br-posix/
개발 환경 설정
기기의 Android 개발 환경을 이미 설정한 Android 기기 공급업체는 이 섹션을 건너뛰어도 됩니다.
Android 생태계에 익숙하지 않거나 Thread 칩을 Android와 호환되도록 만들고 기기 공급업체를 지원하려는 칩 공급업체인 경우 계속 읽어보세요.
Android 개발자 Codelab 따라하기
Android 개발 환경을 처음 설정하려면 다음 Codelab(https://source.android.com/docs/setup/start)을 사용하세요. 이 Codelab을 마치면 소스 코드에서 시뮬레이션된 Cuttlefish 기기를 빌드하고 실행할 수 있습니다.
스레드 HAL 서비스 빌드
Cuttlefish에서 Thread 사용해 보기
Cuttlefish는 가상 Android 기기입니다. 자체 HAL 서비스를 빌드하기 전에 Cuttlefish에서 Thread를 사용하여 HAL의 작동 방식을 이해하는 것이 좋습니다.
기본 Thread HAL 서비스는 Cuttlefish에서 제공되며, UDP 소켓을 통해 시뮬레이션된 Thread (802.15.4) 무선으로 패킷을 송수신하는 시뮬레이션된 RCP로 구현됩니다.
Cuttlefish 인스턴스에는 'ThreadNetworkDemoApp'이 사전 설치되어 있습니다. 이 앱을 열어 Cuttlefish 기기를 기본 스레드 네트워크에 연결합니다.
테스트를 위해 Thread 네트워크를 구성하는 데 제공되는 ot-ctl
및 ot-cli-ftd
명령줄 도구도 있습니다. 이러한 도구는 이미 익숙할 수 있는 모든 OpenThread CLI 명령어를 지원합니다.
다음과 같이 Cuttlefish Thread HAL 서비스의 로그를 grep할 수 있습니다.
adb logcat | egrep -i threadnetwork-service
07-21 10:43:05.048 0 0 I init : Parsing file /apex/com.android.hardware.threadnetwork/etc/threadnetwork-service.rc...
07-21 10:59:27.233 580 580 W android.hardware.threadnetwork-service: ThreadChip binder is unlinked
07-21 10:59:27.233 580 580 I android.hardware.threadnetwork-service: Close IThreadChip successfully
07-21 10:59:27.385 580 580 I android.hardware.threadnetwork-service: Open IThreadChip successfully
또는 다음과 같이 ot-daemon 로그를 grep합니다.
adb logcat | egrep -i ot-daemon
07-21 10:43:48.741 0 0 I init : starting service 'ot-daemon'...
07-21 10:43:48.742 0 0 I init : Created socket '/dev/socket/ot-daemon/thread-wpan.sock', mode 660, user 1084, group 1084
07-21 10:43:48.762 0 0 I init : ... started service 'ot-daemon' has pid 2473
07-21 10:46:26.320 2473 2473 I ot-daemon: [I] P-Daemon------: Session socket is ready
07-21 10:46:30.290 2473 2473 W ot-daemon: [W] P-Daemon------: Daemon read: Connection reset by peer
07-21 10:48:07.264 2473 2473 I ot-daemon: [INFO]-BINDER--: Start joining...
07-21 10:48:07.267 2473 2473 I ot-daemon: [I] Settings------: Saved ActiveDataset
07-21 10:48:07.267 2473 2473 I ot-daemon: [I] DatasetManager: Active dataset set
07-21 10:48:07.273 2473 2473 I ot-daemon: [I] DnssdServer---: Started
07-21 10:48:07.273 2473 2473 I ot-daemon: [N] Mle-----------: Role disabled -> detached
07-21 10:48:07.273 2473 2473 I ot-daemon: [I] Mle-----------: AttachState Idle -> Start
07-21 10:48:07.273 2473 2473 I ot-daemon: [I] Notifier------: StateChanged (0x111fd11d) [Ip6+ Role LLAddr MLAddr KeySeqCntr Ip6Mult+ Channel PanId NetName ExtPanId ...
07-21 10:48:07.273 2473 2473 I ot-daemon: [I] Notifier------: StateChanged (0x111fd11d) ... NetworkKey PSKc SecPolicy NetifState ActDset]
Cuttlefish Thread HAL 서비스는 기본 Thread HAL 서비스와 OpenThread 시뮬레이션된 RCP 바이너리를 사용합니다. 작동 방식은 다음 섹션을 참고하세요.
기본 HAL 서비스
기본 HAL 서비스가 Thread HAL API와 함께 포함되어 있습니다. 기본 HAL 서비스는 시뮬레이션된 RCP 기기와 실제 RCP 기기를 모두 지원합니다. 선택적 RCP 기기 URL을 수신하며 URL이 제공되지 않으면 기본적으로 시뮬레이션된 RCP 기기로 설정됩니다.
hardware/interfaces/threadnetwork/aidl/default/threadnetwork-service.rc
파일에서 다음을 실행합니다.
service vendor.threadnetwork_hal /apex/com.android.hardware.threadnetwork/bin/hw/android.hardware.threadnetwork-service class hal user thread_network
이는 다음과 동일합니다.
service vendor.threadnetwork_hal /apex/com.android.hardware.threadnetwork/bin/hw/android.hardware.threadnetwork-service spinel+hdlc+forkpty:///apex/com.android.hardware.threadnetwork/bin/ot-rcp?forkpty-arg=1 class hal user thread_network
실제 RCP 기기의 경우 SPI 및 UART 인터페이스를 모두 지원하며 스키마 spinel+spi://
, spinel+hdlc+uart://
, spinel+socket://
로 기기를 각각 지정할 수 있습니다.
공급업체 APEX 이해
테더링 메인라인 모듈의 스레드 스택과 마찬가지로 Cuttlefish의 기본 스레드 HAL 서비스도 APEX 모듈에 패키징됩니다. 하지만 /vendor/apex/
에 설치되는 공급업체 APEX 모듈입니다. 모듈의 아티팩트는 /apex/com.android.hardware.threadnetwork/
로 압축 해제됩니다.
apex { name: "com.android.hardware.threadnetwork", manifest: "manifest.json", file_contexts: "file_contexts", key: "com.android.hardware.key", certificate: ":com.android.hardware.certificate", updatable: false, vendor: true, binaries: [ "android.hardware.threadnetwork-service", "ot-rcp", ], prebuilts: [ "threadnetwork-default.xml", // vintf_fragment "threadnetwork-service.rc", // init_rc "android.hardware.thread_network.prebuilt.xml", // permission ], }
자체 HAL APEX 모듈을 빌드할 때 주의하거나 변경해야 하는 몇 가지 중요한 구성이 있습니다.
file_contexts
: 이 APEX 모듈에서 전송된 바이너리 / 데이터 파일 또는 HAL 서비스가 액세스해야 하는 파일 (예: RCP 기기)을 설명합니다. 이렇게 하면 HAL 서비스가 하드웨어 RCP 기기에 액세스할 수 있도록 특정 sepolicy 규칙을 지정할 수 있습니다.binaries
: 이 APEX 모듈에서 제공되는 바이너리 파일입니다.threadnetwork-service.rc
: HAL 서비스가 시작되는 방식입니다. 여기에서 RCP 기기 경로를 지정해야 합니다.android.hardware.thread_network.prebuilt.xml
:android.hardware.thread_network
하드웨어 기능을 정의합니다. 이는 Android 시스템이 기기에 스레드 하드웨어 지원이 있는지 알 수 있도록 하기 위한 것입니다. 그렇지 않으면 Android 스레드 스택이 사용 설정되지 않습니다.
HAL 서비스 만들기
Android 기기 개발자이든 칩 공급업체이든 Thread 칩용 OT RCP 펌웨어 빌드에 익숙해야 합니다. 다음 안내는 하드웨어 칩이 올바르게 배선되고 유효성을 검사했다고 가정합니다.
HAL APEX를 빌드하는 가장 간단한 방법은 기본 HAL APEX의 바이너리 및 사전 빌드된 항목으로 새 APEX를 만드는 것입니다. 예를 들어 회사가 Banana이고 기기의 RCP 기기가 /dev/ttyACM0
이면 Thread HAL APEX는 다음과 같습니다.
Android.bp
:
prebuilt_etc { name: "banana-threadnetwork-service.rc", src: "banana-threadnetwork-service.rc", installable: false, } apex { name: "com.banana.android.hardware.threadnetwork", manifest: "manifest.json", file_contexts: "file_contexts", key: "com.android.hardware.key", certificate: ":com.android.hardware.certificate", updatable: false, vendor: true, binaries: [ "android.hardware.threadnetwork-service", ], prebuilts: [ "banana-threadnetwork-service.rc", "threadnetwork-default.xml", "android.hardware.thread_network.prebuilt.xml", ], }
file_contexts
:
(/.*)? u:object_r:vendor_file:s0 /etc(/.*)? u:object_r:vendor_configs_file:s0 /bin/hw/android\.hardware\.threadnetwork-service u:object_r:hal_threadnetwork_default_exec:s0 /dev/ttyACM0 u:object_r:threadnetwork_rcp_device:s0
첫 번째 열의 파일 경로는 /apex/com.android.hardware.threadnetwork/
와 관련이 있습니다.
threadnetwork-service.rc
:
service vendor.threadnetwork_hal /apex/com.android.hardware.threadnetwork/bin/hw/android.hardware.threadnetwork-service spinel+hdlc+uart:///dev/ttyACM0?uart-baudrate=115200 class hal user root
manifest.json
:
{ "name": "com.android.hardware.threadnetwork", "version": 1 }
Orange라는 새 기기를 만든다고 가정하면 기기별 구성 디렉터리는 다음과 같습니다.
device/banana/orange/threadnetwork/ sepolicy/ Android.bp file_contexts manifest.json threadnetwork-default.xml threadnetwork-service.rc
sepolicy/
하위 디렉터리에 추가해야 하는 sepolicy 규칙은 다음 섹션을 참고하세요.
RCP 기기의 Sepolicy 규칙
기본적으로 Thread HAL 서비스는 RCP 기기 (예: /dev/ttyACM0
)에 액세스할 수 없으므로 맞춤 sepolicy 규칙을 sepolicy/
디렉터리에 추가해야 합니다.
다음 콘텐츠로 새 sepolicy/threadnetwork_hal.te
파일을 만듭니다.
type threadnetwork_rcp_device, dev_type; # Allows the Thread HAL service to read / write the Thread RCP device allow hal_threadnetwork_default threadnetwork_rcp_device:chr_file rw_file_perms;
종합
이제 스레드 추가에 필요한 거의 모든 코드를 완료했습니다. 마지막 단계는 기기의 이미지에 스레드 HAL APEX 및 sepolicy 규칙을 추가하는 것입니다.
이렇게 하려면 기기의 Makefile
(예: device.mk
)에 아래 코드를 추가하면 됩니다.
PRODUCT_PACKAGES += com.banana.hardware.threadnetwork BOARD_SEPOLICY_DIRS += device/banana/orange/threadnetwork/sepolicy
모든 것이 제대로 작동하면 다음과 유사한 스레드 HAL 서비스 로그가 표시됩니다.
adb logcat | egrep -i threadnetwork-service
08-13 13:26:41.751 477 477 I android.hardware.threadnetwork-service: ServiceName: android.hardware.threadnetwork.IThreadChip/chip0, Url: spinel+spi
08-13 13:26:41.751 477 477 I android.hardware.threadnetwork-service: Thread Network HAL is running
08-13 13:26:55.165 477 477 I android.hardware.threadnetwork-service: Open IThreadChip successfully
ot-daemon
로그는 다음과 같습니다.
adb logcat -s ot-daemon
08-13 13:26:55.157 1019 1019 I ot-daemon: [NOTE]-AGENT---: Running OTBR_AGENT/Unknown
08-13 13:26:55.157 1019 1019 I ot-daemon: [NOTE]-AGENT---: Thread version: 1.3.0
08-13 13:26:55.157 1019 1019 I ot-daemon: [NOTE]-AGENT---: Thread interface: thread-wpan
08-13 13:26:55.157 1019 1019 I ot-daemon: [NOTE]-AGENT---: Backbone interface is not specified
08-13 13:26:55.157 1019 1019 I ot-daemon: [NOTE]-AGENT---: Radio URL: threadnetwork_hal://binder?none
08-13 13:26:55.157 1019 1019 I ot-daemon: [NOTE]-ILS-----: Infra link selected:
08-13 13:26:55.160 1019 1019 I ot-daemon: [I] Platform------: [HAL] Wait for getting the service android.hardware.threadnetwork.IThreadChip/chip0 ...
08-13 13:26:55.165 1019 1019 I ot-daemon: [I] Platform------: [HAL] Successfully got the service android.hardware.threadnetwork.IThreadChip/chip0
08-13 13:26:55.275 1019 1019 I ot-daemon: [I] P-RadioSpinel-: RCP reset: RESET_UNKNOWN
08-13 13:26:55.276 1019 1019 I ot-daemon: [I] P-RadioSpinel-: Software reset RCP successfully
08-13 13:26:55.277 1019 1019 I ot-daemon: [I] P-RadioSpinel-: RCP reset: RESET_POWER_ON
08-13 13:26:55.322 1019 1019 I ot-daemon: [I] ChildSupervsn-: Timeout: 0 -> 190
08-13 13:26:55.324 1019 1019 I ot-daemon: [I] RoutingManager: Initializing - InfraIfIndex:0
08-13 13:26:55.324 1019 1019 I ot-daemon: [I] InfraIf-------: Init infra netif 0
08-13 13:26:55.324 1019 1019 I ot-daemon: [I] Settings------: Read BrUlaPrefix fd7b:cc45:ff06::/48
08-13 13:26:55.324 1019 1019 I ot-daemon: [N] RoutingManager: BR ULA prefix: fd7b:cc45:ff06::/48 (loaded)
08-13 13:26:55.324 1019 1019 I ot-daemon: [I] RoutingManager: Generated local OMR prefix: fd7b:cc45:ff06:1::/64
08-13 13:26:55.324 1019 1019 I ot-daemon: [N] RoutingManager: Local on-link prefix: fdde:ad00:beef:cafe::/64
08-13 13:26:55.324 1019 1019 I ot-daemon: [I] RoutingManager: Enabling
맞춤설정
스레드 메인라인 모듈 (실제로는 '테더링' 모듈의 일부)은 공급업체가 스택 동작을 맞춤설정하기 위해 지정할 수 있는 몇 가지 오버레이 가능한 구성을 제공합니다. 전체 목록은 config_thread.xml을 참고하세요.
일반적으로 기기를 스레드 보더 라우터로 사용 설정하려면 config_thread_border_router_default_enabled
를 true
로 설정하고 config_thread_vendor_name
, config_thread_vendor_oui
, config_thread_model_name
를 공급업체 또는 제품 값으로 변경해야 합니다. 이러한 값은 항상 스레드 경계 라우터에서 광고하는 _meshcop._udp
mDNS 서비스에 포함됩니다.
오버레이를 추가하려면 Orange 기기용 새 ConnectivityOverlayOrange
runtime_resource_overlay 타겟을 만들어야 합니다. device/banana/orange/rro_overlays
아래에 새 ConnectivityOverlay/
디렉터리를 만들고 아래 콘텐츠를 만듭니다.
device/banana/orange/rro_overlays/ConnectivityOverlay/ res values config_thread.xml Android.bp AndroidManifest.xml
Android.bp
:
package { default_applicable_licenses: ["Android-Apache-2.0"], } runtime_resource_overlay { name: "ConnectivityOverlayOrange", manifest: "AndroidManifest.xml", resource_dirs: ["res"], certificate: "platform", product_specific: true, sdk_version: "current", }
AndroidManifest.xml
:
<!-- Orange overlays for the Connectivity module --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.banana.android.connectivity.resources.orange" android:versionCode="1" android:versionName="1.0"> <application android:hasCode="false" /> <!-- If your device uses google-signed mainline modules, the targetPackage needs to be "com.google.android.connectivity.resources", otherise, it should be "com.android.connectivity.resources" --> <overlay android:targetPackage="com.google.android.connectivity.resources" android:targetName="ServiceConnectivityResourcesConfig" android:isStatic="true" android:priority="1"/> </manifest>
config_thread.xml
:
<bool name="config_thread_border_router_default_enabled">true</bool> <string translatable="false" name="config_thread_vendor_name">Banana Inc.</string> <string translatable="false" name="config_thread_vendor_oui">AC:DE:48</string> <string translatable="false" name="config_thread_model_name">Orange</string>
HAL APEX와 마찬가지로 device.mk
파일에 오버레이 앱을 추가해야 합니다.
PRODUCT_PACKAGES += \ ConnectivityOverlayOrange</code>
모든 것이 제대로 작동하면 ot-daemon
가 로그의 맨 처음에 공급업체 및 모델 이름을 로깅합니다.
adb logcat -s ot-daemon
07-22 15:31:37.693 1472 1472 I ot-daemon: [I] P-Daemon------: Session socket is ready
07-22 15:31:37.693 1472 1472 I ot-daemon: [I] Cli-----------: Input: state
07-22 15:31:37.693 1472 1472 I ot-daemon: [I] Cli-----------: Output: disabled
07-22 15:31:37.693 1472 1472 I ot-daemon: [I] Cli-----------: Output: Done
07-22 15:31:37.693 1472 1472 W ot-daemon: [W] P-Daemon------: Daemon read: Connection reset by peer
07-22 15:31:50.091 1472 1472 I ot-daemon: [I] P-Daemon------: Session socket is ready
07-22 15:31:50.091 1472 1472 I ot-daemon: [I] Cli-----------: Input: factoryreset
07-22 15:31:50.092 1472 1472 I ot-daemon: [I] Settings------: Wiped all info
07-22 15:31:50.092 1472 1472 I ot-daemon: [INFO]-ADPROXY-: Stopped
07-22 15:31:50.092 1472 1472 I ot-daemon: [INFO]-DPROXY--: Stopped
07-22 15:31:50.092 1472 1472 I ot-daemon: [INFO]-BA------: Stop Thread Border Agent
07-22 15:31:50.092 1472 1472 I ot-daemon: [INFO]-BA------: Unpublish meshcop service Banana Inc. Orange #4833._meshcop._udp.local
07-22 15:31:50.092 1472 1472 I ot-daemon: [INFO]-MDNS----: Removing service Banana Inc. Orange #4833._meshcop._udp
07-22 15:31:50.092 1472 1472 I ot-daemon: [INFO]-MDNS----: Unpublishing service Banana Inc. Orange #4833._meshcop._udp listener ID = 0
Google Home과 호환됨
또한 Google Home 생태계에서 Border Router를 사용하도록 하려면 config_thread.xml
에서 이 구성을 지정하면 됩니다.
<string-array name="config_thread_mdns_vendor_specific_txts"> <item>vgh=1</item> </string-array>
테스트
이제 기기가 Thread 1.3 이상 보더 라우터 사양과 호환됩니다. Thread 인증 프로그램에 전송하기 전에 호환성을 보장하기 위해 몇 가지 Android xTS 테스트를 실행해야 합니다.
VTS 테스트는 기기에서 Thread HAL 서비스가 예상대로 작동하는지 확인합니다. 다음 명령어로 테스트를 실행할 수 있습니다.
atest VtsHalThreadNetworkTargetTest
CTS 테스트는 Thread API가 기기에서 예상대로 작동하는지 확인합니다. 다음 명령어를 사용하여 테스트를 실행할 수 있습니다.
atest CtsThreadNetworkTestCases
통합 테스트는 스레드 메인라인 코드가 기기에서 작동하는 방식에 대한 품질 보증을 강화합니다. 다음 명령어로 테스트를 실행할 수 있습니다.
atest ThreadNetworkIntegrationTests
이러한 출시된 테스트 모음으로 VTS/CTS/MTS 테스트를 실행하는 방법에 관한 자세한 안내는 다음을 참고하세요.
- https://source.android.com/docs/core/tests/vts
- https://source.android.com/docs/compatibility/cts/run
- https://docs.partner.android.com/mainline/test/mts (이 링크에 액세스하려면 파트너여야 함)
Thread 데모 앱으로 테스트
Cuttlefish 기기와 마찬가지로 시스템 이미지에 Thread 데모 앱을 추가할 수 있습니다.
# ThreadNetworkDemoApp for testing PRODUCT_PACKAGES_DEBUG += ThreadNetworkDemoApp
이는 최종 소비자용 사용자 빌드에 포함되어서는 안 되므로 디버그 / eng 변형 (예: PRODUCT_PACKAGES_DEBUG
)에만 추가해야 합니다.