Visualizza origine su Android Code Search
Se non sei un produttore di dispositivi Android o chip Thread, puoi smettere di leggere subito.
Questo documento illustra la procedura per creare un nuovo dispositivo Thread Border Router basato su Android con il codice sorgente AOSP più recente. Seguendo questo documento, imparerai:
- l'architettura e lo stato generale del supporto di Thread in Android
- Come creare il tuo servizio HAL Thread
- Come rendere il tuo dispositivo compatibile con Google Home
- Come testare il router di confine Thread
Se hai bisogno di assistenza, invia una segnalazione su GitHub o apri una discussione se hai domande.
Panoramica
Lo stack Thread di Android si basa su OpenThread e ot-br-posix
, che sono
sviluppati in open source da Google su GitHub. Come OpenThread viene sviluppato in un
repository GitHub pubblico, lo stack Android Thread viene sviluppato nel
codebase AOSP pubblico. Tutte le funzionalità e le correzioni di bug vengono inviate prima in AOSP. In questo modo, i fornitori possono iniziare ad adottare le ultime versioni di Thread senza attendere le release regolari di Android.
Architettura
L'intero stack Thread di Android è costituito da due componenti principali: lo stack Thread di base in una partizione di sistema generica e il servizio HAL Thread in una partizione del fornitore. In genere, i fornitori di dispositivi devono solo occuparsi e creare il servizio HAL.
Ecco un breve riepilogo del funzionamento dello stack Thread di Android:
- Nel server di sistema è presente un servizio di sistema Thread Java che gestisce l'intero stack, fornisce l'API di sistema Thread, crea l'interfaccia del tunnel thread-wpan
, registra la rete Thread nel servizio di connettività e implementa le funzionalità di Border Routing e Advertising Proxy.
- Lo stack Thread / OpenThread principale è ospitato in un processo nativo autonomo non privilegiato denominato ot-daemon
. ot-daemon
è gestito direttamente dal servizio di sistema Java tramite API AIDL private e accede alla radio hardware Thread tramite l'API HAL Thread.
- Un servizio HAL Thread fornito dal fornitore DEVE implementare l'API HAL Thread. In genere, funziona come RCP e implementa il protocollo spinel.
Dove si trova il codice?
- Il framework / l'API e il servizio Thread di Android: https://cs.android.com/android/platform/superproject/main/+/main:packages/modules/Connectivity/thread/
- L'API HAL Thread e l'implementazione del servizio predefinito: https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/threadnetwork/
- Repository OpenThread importato: https://cs.android.com/android/platform/superproject/main/+/main:external/openthread/
- Repository ot-br-posix importato: https://cs.android.com/android/platform/superproject/main/+/main:external/ot-br-posix/
Configura l'ambiente di sviluppo
I fornitori di dispositivi Android che hanno già creato un ambiente di sviluppo Android per il dispositivo possono saltare questa sezione.
Se non hai dimestichezza con l'ecosistema Android o sei un fornitore di silicio che vuole trovare una soluzione per rendere il proprio chip Thread compatibile con Android e fornire assistenza ai fornitori di dispositivi, continua a leggere.
Segui il codelab per sviluppatori Android
Per configurare l'ambiente di sviluppo Android per la prima volta, utilizza il seguente codelab: https://source.android.com/docs/setup/start. Al termine di questo codelab, potrai creare ed eseguire un dispositivo Cuttlefish simulato dal codice sorgente.
Crea il servizio HAL Thread
Provare Thread in Cuttlefish
Cuttlefish è il dispositivo Android virtuale. Prima di iniziare a creare il tuo servizio HAL, è meglio provare Thread in Cuttlefish per capire come funziona HAL.
In Cuttlefish è fornito un servizio HAL Thread predefinito ed è implementato con il RCP simulato che trasmette e riceve pacchetti tramite socket UDP verso e da una radio Thread (802.15.4) simulata.
Nell'istanza Cuttlefish è preinstallata un'app "ThreadNetworkDemoApp". Apri l'app per collegare il dispositivo Cuttlefish a una rete Thread predefinita.
Sono inoltre disponibili gli strumenti a riga di comando ot-ctl
e ot-cli-ftd
per configurare la rete Thread per i test. Questi strumenti supportano tutti i comandi della CLI OpenThread che potresti già conoscere.
Puoi cercare i log del servizio HAL Thread di Cuttlefish utilizzando 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
In alternativa, cerca i log di ot-daemon utilizzando:
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]
Il servizio HAL Thread di Cuttlefish utilizza il servizio HAL Thread predefinito più il programma binario RCP simulato di OpenThread. Per scoprire come funziona, consulta la sezione successiva.
Il servizio HAL predefinito
Un servizio HAL predefinito è incluso insieme all'API HAL Thread. Il servizio HAL predefinito supporta sia i dispositivi RCP simulati sia quelli reali. Riceve un URL del dispositivo RCP facoltativo e, se l'URL non viene fornito, viene utilizzato per impostazione predefinita il dispositivo RCP simulato.
Nel file 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
Ciò equivale a:
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
Per i dispositivi RCP reali, supporta sia le interfacce SPI sia UART e puoi specificare il dispositivo rispettivamente con gli schemi spinel+spi://
, spinel+hdlc+uart://
e
spinel+socket://
.
Informazioni sull'APEX del fornitore
Analogamente allo stack Thread nel modulo principale del tethering, il servizio Thread HAL predefinito in Cuttlefish è pacchettizzato anche in un modulo APEX. Tuttavia, si tratta di un
modulo APEX del fornitore che verrà installato in /vendor/apex/
(gli elementi nel
modulo verranno decompressi in /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 ], }
Esistono alcune configurazioni importanti a cui devi prestare attenzione o apportare modifiche quando crei il tuo modulo HAL APEX:
file_contexts
: descrive i file di dati / binari caricati in questo modulo APEX o i file a cui il servizio HAL deve accedere (ad esempio il dispositivo RCP). In questo modo puoi specificare regole sepolicy specifiche per il servizio HAL per accedere al dispositivo RCP hardware.binaries
: il file binario fornito in questo modulo APEXthreadnetwork-service.rc
: la modalità di avvio del servizio HAL. Devi specificare il percorso del dispositivo RCP qui.android.hardware.thread_network.prebuilt.xml
: definisce la funzionalità hardwareandroid.hardware.thread_network
. Questo è necessario per consentire al sistema Android di sapere che il tuo dispositivo supporta l'hardware Thread. In caso contrario, lo stack Thread di Android non verrà attivato.
Crea il servizio HAL
Che tu sia uno sviluppatore di dispositivi Android o un fornitore di silicio, devi conoscere la creazione del firmware OT RCP per il tuo chip Thread. Le seguenti istruzioni presuppongono che il chip hardware sia cablato e convalidato correttamente.
Il modo più semplice per compilare il tuo APEX HAL è creare un nuovo APEX con i file binari e precompilati dell'APEX HAL predefinito. Ad esempio, se la tua azienda è Banana e il dispositivo RCP sul tuo dispositivo è /dev/ttyACM0
, il tuo Thread HAL APEX sarà simile al seguente:
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
I percorsi file nella prima colonna sono relativi a /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 }
Supponendo che tu stia creando un nuovo dispositivo denominato Arancione, la directory di configurazione specifica del dispositivo sarà simile alla seguente:
device/banana/orange/threadnetwork/ sepolicy/ Android.bp file_contexts manifest.json threadnetwork-default.xml threadnetwork-service.rc
Consulta la sezione successiva per sapere quali regole sepolicy devono essere aggiunte nella sottodirectory sepolicy/
.
Regole Sepolicy per il dispositivo RCP
Per impostazione predefinita, il servizio HAL Thread non ha accesso al dispositivo RCP (ad esempio /dev/ttyACM0
), pertanto è necessario aggiungere regole sepolicy personalizzate alla directory sepolicy/
.
Crea un nuovo file sepolicy/threadnetwork_hal.te
con i seguenti contenuti:
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;
Mettere insieme
Ora hai completato quasi tutte le esigenze di codice per l'aggiunta di Thread. L'ultimo passaggio consiste nell'aggiungere le regole sepolicy e APEX HAL di Thread all'immagine del dispositivo.
Aggiungi il codice riportato di seguito a Makefile
del tuo dispositivo (ad esempio,
device.mk
):
PRODUCT_PACKAGES += com.banana.hardware.threadnetwork BOARD_SEPOLICY_DIRS += device/banana/orange/threadnetwork/sepolicy
Se tutto funziona, ora potrai vedere il log del servizio HAL Thread simile al seguente:
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
Il log ot-daemon
sarà simile al seguente:
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
Personalizzazione
Il modulo Thread principale (in realtà fa parte del modulo "Tethering") fornisce alcune configurazioni sovrapponibili che possono essere specificate dai fornitori per personalizzare il comportamento dello stack. Consulta config_thread.xml per l'elenco completo.
In genere, devi impostare config_thread_border_router_default_enabled
su true
per attivare il dispositivo come router di confine Thread e modificare
config_thread_vendor_name
, config_thread_vendor_oui
e
config_thread_model_name
in base ai valori del fornitore o del prodotto. Questi valori verranno inclusi nel servizio mDNS _meshcop._udp
, che viene sempre pubblicizzato da un router di confine Thread.
Per aggiungere l'overlay, devi creare un nuovo target ConnectivityOverlayOrange
runtime_resource_overlay per il tuo dispositivo Orange. Crea una nuova directory ConnectivityOverlay/
in device/banana/orange/rro_overlays
e inserisci i seguenti contenuti:
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>
Come per HAL APEX, devi aggiungere l'app in overlay al file device.mk
:
PRODUCT_PACKAGES += \ ConnectivityOverlayOrange</code>
Se tutto funziona, vedrai che ot-daemon
registra il nome del fornitore e del modello
all'inizio del log:
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
Essere compatibile con Google Home
Inoltre, se vuoi che il tuo router di confine venga utilizzato dall'ecosistema Google Home, puoi specificare questa configurazione in config_thread.xml
:
<string-array name="config_thread_mdns_vendor_specific_txts"> <item>vgh=1</item> </string-array>
Test
Il tuo dispositivo dovrebbe ora essere compatibile con la specifica del router di confine Thread 1.3 o versioni successive. Prima di inviarlo al programma di certificazione Thread, devono essere eseguiti alcuni test xTS Android per garantire la compatibilità.
Il test VTS garantisce che il servizio HAL Thread funzioni come previsto sul dispositivo. Puoi eseguire i test con il comando
atest VtsHalThreadNetworkTargetTest
Il test CTS garantisce che le API Thread funzionino come previsto sul dispositivo. Puoi eseguire i test con il comando
atest CtsThreadNetworkTestCases
Il test di integrazione offre una maggiore garanzia di qualità del funzionamento del codice di Thread mainline sul tuo dispositivo. Puoi eseguire i test con il comando
atest ThreadNetworkIntegrationTests
Puoi anche trovare ulteriori istruzioni su come eseguire i test VTS/CTS/MTS con queste suite di test rilasciate:
- https://source.android.com/docs/core/tests/vts
- https://source.android.com/docs/compatibility/cts/run
- https://docs.partner.android.com/mainline/test/mts (per accedere a questo link devi essere un partner)
Eseguire il test con l'app demo Thread
Come per il dispositivo Cuttlefish, puoi aggiungere l'app di dimostrazione Thread all'immagine di sistema:
# ThreadNetworkDemoApp for testing PRODUCT_PACKAGES_DEBUG += ThreadNetworkDemoApp
Tieni presente che devi aggiungerlo solo alla variante di debug / eng (ad es.PRODUCT_PACKAGES_DEBUG
), poiché non deve essere inclusa nella build dell'utente per i consumatori finali.