L'articolo tratta il ciclo di vita della sessione Aware (solo Android), il
modello di discovery publish / subscribe, l'handshake a due fasi con
role-split che sincronizza requestNetwork su entrambi i lati entro la
finestra di ~500 ms del framework, il pool di link per-peer con idle sweeping,
il trucco IPv6 + DNS custom che consente a un singolo client OkHttp di servire
sia LAN sia Aware, e il prewarmer che innesca l'avvio di Aware sul peer via
BLE.
Per la catena di fallback più ampia, si veda Chat Architecture. Per il trasporto BLE che subentra quando Aware non è disponibile, si veda BLE Transport. Per come viene stabilita la chiave ChaCha20 condivisa riusata come PMK di Aware, si veda Pairing Flow.
Sommario
- Perché Wi-Fi Aware?
- Dove si posiziona Aware nella catena di fallback
- Ciclo di vita della sessione: Attach → Publish + Subscribe
- Discovery e assegnazione dei ruoli
- L'handshake a due fasi (hello + ready)
- NDP requestNetwork — la finestra di 500 ms
- Pool di link per-peer e idle sweeping
- Indirizzamento IPv6 e il trucco DNS
plain-aware-peer - Crittografia: derivazione PMK e riuso di ChaCha20
- Percorso di invio messaggi (end-to-end)
- Percorso di download file (end-to-end)
- Prewarming: avvio di Aware innescato da BLE
- Modalità di fallimento e il flag fast-skip
- Riferimento delle costanti chiave
- Riepilogo dei compromessi di design
Perché Wi-Fi Aware? {#why-wi-fi-aware}
Wi-Fi Aware (IEEE 802.11bc, formalmente NAN — Neighbor Awareness Networking) è una certificazione Wi-Fi Alliance che permette a due dispositivi di scoprirsi a vicenda e scambiare dati senza alcuna infrastruttura Wi-Fi — nessun AP, nessun router, nessun DHCP. PlainApp lo usa per due scenari che LAN non può coprire:
- SSID / VLAN diversi. Un telefono sulla rete guest e un laptop sulla VLAN IoT sono entrambi «online» via Wi-Fi ma non possono raggiungere l'IP dell'altro. Aware crea un data path diretto device-to-device che bypassa completamente l'infrastruttura.
- Nessuna infrastruttura. Due dispositivi in mezzo al nulla con il Wi-Fi acceso ma senza AP possono comunque chattare. (BLE copre questo, ma Aware è molto più veloce — ~10 ms di round trip contro secondi, e MB/s contro decine di KB/s.)
Vincoli di piattaforma
Wi-Fi Aware è solo Android in PlainApp:
- Android 13 (API 33) è il minimo — gli overload di
WifiAwareNetworkSpecifier.BuilderconsetPort()esetPmk()da cui PlainApp dipende richiedonoisTPlus(). - iOS non espone Wi-Fi Aware alle app di terze parti. iOS PlainApp cade
direttamente da LAN a BLE; l'oggetto
WifiAwareTransportnon è nemmeno compilato nel target iOS (@RequiresApi(Build.VERSION_CODES.S)+ source set androidMain).
Ecco perché PeerTransportRouter.buildList chiama
createWifiAwareTransport() — una factory che ritorna null su iOS.
Dove si posiziona Aware nella catena di fallback {#where-aware-sits-in-the-fallback-chain}
Il PeerTransportRouter di PlainApp è una lista ordinata. Per ogni chiamata
send o downloadFile, percorre la lista e prova ogni trasporto finché uno
non ha successo; i fallimenti si propagano in basso.
Perché Aware è «il mezzo» e non «il primo»?
Perché LAN è quasi sempre più veloce quando disponibile. Un salto Wi-Fi stessa subnet attraverso un AP è un singolo scambio di frame 802.11; un data path Aware aggiunge un setup NDP (~5 s al primo uso) più un secondo contesto radio Wi-Fi per il link device-to-device. Se entrambi sono raggiungibili, LAN vince su latenza e throughput.
Viceversa, BLE è sempre più lento — ma funziona ogni volta che entrambi i dispositivi sono paired. Aware sta in mezzo: più veloce di BLE, più lento di LAN, e disponibile solo su dispositivi Android 13+ con il Wi-Fi acceso.
Ciclo di vita della sessione: Attach → Publish + Subscribe {#session-lifecycle-attach--publish--subscribe}
Una sessione Wi-Fi Aware è process-wide. C'è esattamente una
WifiAwareSession per dispositivo; al suo interno, PlainApp fa girare una
sessione di publish (così i peer possono scoprirci) e una sessione di
subscribe (così possiamo scoprire i peer). Entrambe vengono avviate non
appena AwareSession.start() completa la callback di attach.
Perché publish AND subscribe sullo stesso dispositivo?
Il modello di discovery di Wi-Fi Aware è asimmetrico: un publisher
publicizza un servizio, un subscriber lo scansiona. Per rendere simmetrico il
discovery (entrambi i dispositivi si scoprono a vicenda), PlainApp fa
entrambe le cose in una volta. Senza questo, il dispositivo A dovrebbe
sapere in anticipo se è il publisher o il subscriber per un dato peer — ma i
ruoli dei peer sono determinati più tardi dal confronto di clientId (si veda
Discovery & Role Assignment).
Pubblicare e fare subscribe simultaneamente significa che ciascun dispositivo
vede l'onServiceDiscovered dell'altro (come subscriber) E riceve i messaggi
hello dell'altro (come publisher) — entrambe le direzioni dell'handshake sono
sempre disponibili.
Auto-restart su terminazione
Alcune varianti Android (MIUI in particolare) uccidono le sessioni Aware di
lunga durata per risparmiare batteria. PlainApp lo gestisce nelle callback di
onSessionTerminated: mette a null la sessione terminata e richiama
immediatamente publishOwnService / subscribeOwnService sulla
WifiAwareSession ancora attached. La sessione di attach stessa non viene
persa — solo la sessione di discovery publish/subscribe. I peer handle da
prima della terminazione diventano stale, ecco perché awaitPeerHandle
controlla il timestamp discoveredAt e scarta gli handle più vecchi di 30 s.
Discovery e assegnazione dei ruoli {#discovery--role-assignment}
Il protocollo data-path di Wi-Fi Aware richiede che un lato agisca come publisher (server) e l'altro come subscriber (client). Entrambe le parti non possono essere simultaneamente l'initiator — il framework rifiuta le richieste senza una controparte corrispondente.
PlainApp assegna i ruoli deterministicamente per peer usando un semplice confronto lessicografico dei clientIds:
Perché deterministico e non negoziato?
Un approccio negoziato (ad es. «il MAC più basso è il server») richiederebbe
uno scambio di messaggi extra. Il confronto lessicografico è idempotente,
simmetrico e stateless: entrambi i dispositivi calcolano lo stesso ruolo per
la stessa coppia senza alcuna comunicazione. Il clientId è uno short UUID di
13 caratteri, quindi i pareggi (clientId == peer.id) avvengono solo
confrontando un peer con sé stesso — il che non raggiunge mai il trasporto.
Il ruolo determina due cose a valle:
- Chi guida il retry loop. Solo il client ritenta
requestNetwork; il server fa esattamente un tentativo per ogni hello ricevuto. Questo è critico per la finestra di 500 ms (sezione successiva). - Chi imposta la porta. Il publisher chiama
setPort(httpsPort)perché è lui che accetta connessioni inbound sulla porta del proprio server HTTPS. Il subscriber non imposta una porta — apprende la porta del peer dallaWifiAwareNetworkInfodopo che il data path è stabilito.
L'handshake a due fasi (hello + ready) {#the-two-phase-handshake-hello--ready}
La parte più difficile del setup del data path Wi-Fi Aware è il timing. Il
framework richiede che entrambe le parti chiamino
connectivityManager.requestNetwork entro circa 500 ms l'una dall'altra — se
un lato la chiama prima che l'altro abbia registrato la propria richiesta
corrispondente, il framework la rifiuta immediatamente con onUnavailable
("releaseRequestAsUnfulfillableByAnyFactory").
PlainApp risolve questo con un handshake a due messaggi a livello
applicativo che gira sopra il canale di messaggi L2 di Aware (la stessa API
sendMessage usata da onServiceDiscovered):
Perché due messaggi (hello + ready) invece di uno solo?
L'hello da solo non basta a causa dell'asimmetria di direzione. Il
subscriber può inviare l'hello non appena scopre il publisher (in
onServiceDiscovered), ma il publisher non può iniziare requestNetwork
finché non ha il PeerHandle del subscriber, che apprende solo ricevendo
l'hello. Quindi l'hello serve a due scopi:
- Consegnare il PeerHandle del subscriber al publisher. Il publisher ne
ha bisogno per costruire il
WifiAwareNetworkSpecifier. - Segnalare l'intento di connettersi. Ricevere l'hello dice al publisher «il subscriber sta per fare requestNetwork, quindi dovrei farlo anch'io».
La ricevuta ready esiste per la direzione opposta — per dire al
subscriber «il publisher ha registrato il proprio requestNetwork». Senza di
essa, il requestNetwork del subscriber potrebbe arrivare prima di quello
del publisher ed essere rifiutato dal framework. La ricevuta ready è un
segnale non bloccante: il subscriber non la attende prima di chiamare
requestNetwork (aggiungerebbe un round trip), ma se arriva mentre il
subscriber è in stato IDLE (tra tentativi di retry), può ritentare
immediatamente senza attendere il gap RETRY_DELAY_MS.
L'asimmetria del retry loop
Questa è la parte più sottile del design. Solo il subscriber ritenta. Il
publisher fa esattamente un tentativo di requestNetwork per ogni hello
ricevuto. Questo perché:
- Se entrambe le parti ritentassero indipendentemente, i loro cicli di retry
andrebbero fuori fase (diverse durate
delay(), diverse pause GC), e le due chiamaterequestNetworksi sovrapporrebbero raramente dentro la finestra di 500 ms. - Il retry loop del subscriber invia un hello fresco a ogni tentativo, che
re-innesca il
buildLinkdel publisher viapublishHelloListeners. Questo garantisce che ilrequestNetworkdel publisher segua sempre l'hello di ~50 ms, ben dentro la finestra di 500 ms.
Questo è documentato in dettaglio in
AwarePeerLink.build.
NDP requestNetwork — la finestra di 500 ms {#ndp-requestnetwork--the-500-ms-window}
La chiamata requestNetwork è l'operazione più timing-sensitive nel trasporto
Aware. Ecco cosa succede su ciascun lato:
Cosa significa la callback onUnavailable
onUnavailable scatta quando il framework rifiuta il requestNetwork prima
di trovare una richiesta peer corrispondente. Il PeerHandle stesso è ancora
valido — solo l'accoppiamento NDP (Neighbor Discovery Protocol) è fallito
perché l'altro lato non aveva ancora registrato. PlainApp deliberatamente
non chiama session.invalidatePeerHandle in questo caso, perché
invalidare l'handle scarterebbe l'unico segnale che onServiceDiscovered sia
mai stato chiamato (scatta una volta per peer per la durata della sessione di
subscribe). Con l'handle preservato, il retry può riusarlo invece di attendere
una discovery fresca.
Lo stesso vale per l'handle lato publisher proveniente da onMessageReceived —
il publisher mantiene l'entry publishPeerHandles[fromCid] attraverso i
tentativi falliti, così l'hello successivo del subscriber riusa l'handle in
cache invece di essere scartato.
Pool di link per-peer e idle sweeping {#per-peer-link-pool--idle-sweeping}
Ogni peer paired ottiene il proprio oggetto AwarePeerLink, posseduto
dall'AwareLinkPool process-wide. Il pool gestisce gli eventi di discovery,
il riuso dei link e l'evizione degli idle.
Perché nessun auto-build su discovery?
Il pool esplicitamente non costruisce un link quando
onServiceDiscovered scatta. Questa è una decisione critica: uno coffee shop
affollato potrebbe avere 100 dispositivi PlainApp che pubblicano tutti il
servizio «plain-peer». Se ogni discovery innesca un requestNetwork, il
framework verrebbe inondato di tentativi di setup NDP e la radio Wi-Fi
sarebbe saturata.
Invece, il pool registra solo il PeerHandle e attende uno tra:
- L'utente locale invia un messaggio →
WifiAwareTransport.send→pool.buildLink(peer)(trigger lato sender). - Il peer remoto invia un hello →
onPublishHelloReceived→buildLink(peer)(trigger lato receiver). - Il peer remoto invia un ready →
onSubscribeReadyReceived→buildLink(peer)(trigger lato receiver).
In questo modo, i link sono costruiti solo per i peer con cui l'utente sta effettivamente scambiando messaggi — non per ogni dispositivo PlainApp nel raggio radio.
Idle sweep
Ogni 10 secondi, il pool percorre tutti i link e chiude quelli il cui
lastActiveAt è più vecchio di 60 secondi. Ogni send e downloadFile
chiama link.touch() per aggiornare il timestamp. Questo recupera il
contesto radio Wi-Fi e il pool di connessioni OkHttp per i peer con cui
l'utente ha smesso di chattare — importante perché Android limita il numero
di data path Aware simultanei a circa 4–10 (dipendentemente dal dispositivo).
Indirizzamento IPv6 e il trucco DNS plain-aware-peer {#ipv6-addressing--the-plain-aware-peer-dns-trick}
I data path Wi-Fi Aware usano solo IPv6 link-local. Non c'è IPv4, nessun
server DNS, nessun DHCP. L'indirizzo IPv6 del peer è consegnato via il campo
WifiAwareNetworkInfo.peerIpv6Addr in onCapabilitiesChanged — un indirizzo
fe80::... che ha senso solo sull'interfaccia di rete Aware.
PlainApp deve inviare richieste HTTPS a questo indirizzo, ma il parsing URL
https:// di OkHttp rifiuta gli IPv6 letterali raw in un hostname
(https://[fe80::abcd]:8443/ funziona, ma instradarlo attraverso un resolver
Dns custom è più pulito). Il trucco:
Perché un hostname sentinel?
L'alternativa — passare il letterale IPv6 direttamente nell'URL — richiederebbe
che ogni call site sappia dell'indirizzo link-local. Usando un hostname
sentinel, la costruzione dell'URL è identica per LAN e Aware: entrambi
producono un URL https://<host>:<port>/peer_graphql valido che OkHttp può
parsare. L'unica differenza è l'implementazione Dns collegata al client —
LAN usa il DNS di sistema, Aware usa awareDns(peerIpv6) che ritorna
l'indirizzo link-local in cache per l'hostname sentinel e ricade su
Dns.SYSTEM per qualsiasi altra cosa.
Perché network.socketFactory?
L'oggetto Network di Android rappresenta una specifica interfaccia di rete
(in questo caso, il data path Aware). Chiamando network.socketFactory e
passandolo alla config socketFactory di OkHttp, forziamo tutti i socket TCP
ad essere creati sull'interfaccia Aware — non sull'interfaccia Wi-Fi o
cellulare di default. Senza questo, l'OS instraderebbe la richiesta via il
network di default, dove l'IPv6 link-local è irraggiungibile, e la richiesta
fallirebbe con ENETUNREACH.
Crittografia: derivazione PMK e riuso di ChaCha20 {#cryptography-pmk-derivation--chacha20-reuse}
Wi-Fi Aware supporta una PMK (Pairwise Master Key) opzionale per il data path. Quando impostata, il link L2 stesso è cifrato con quella PMK — la radio Wi-Fi gestisce la cifratura, nessuna crittografia a livello applicativo richiesta.
PlainApp deriva la PMK dalla stessa chiave condivisa ChaCha20 che
LanTransport e BleTransport usano per la cifratura a livello applicativo:
Perché troncare a 32 byte?
La PMK di Wi-Fi Aware deve essere esattamente 32 byte (256 bit). La chiave
condivisa ChaCha20 del pairing è anch'essa 32 byte nel caso normale, quindi
il branch raw.size == 32 è il path comune. Il fallback di
troncamento/padding gestisce il caso (teorico) in cui la chiave fosse
memorizzata più corta — il padding con zeri a 32 byte è una misura difensiva,
non qualcosa che accade nella pratica con peer correttamente paired.
L'envelope firmata è identica a LAN
Poiché createCryptoHttpClient è la stessa factory usata da LanTransport,
la crittografia L7 su Aware è byte-per-byte identica a LAN. Il
PeerGraphQLService lato server non sa (né gli importa) quale trasporto abbia
consegnato la richiesta — vede semplicemente un payload GraphQL firmato e
cifrato e lo decifra con la chiave condivisa del peer. Questo è il principio
«una codebase, molti trasporti» documentato in
Chat Architecture.
Percorso di invio messaggi (end-to-end) {#message-send-path-end-to-end}
Mettendo tutto insieme — cosa succede quando un messaggio di chat viene inviato via Wi-Fi Aware:
Scelte di design notevoli
- Riuso della connessione. A differenza di
BleTransport, che abbatte la connessione GATT dopo ogni richiesta,WifiAwareTransportriusa il data path Aware per quante richieste l'utente fa entro la finestra idle di 60 s. La prima richiesta paga l'handshake di ~400 ms; le richieste successive sono ~10 ms di round trip. - Stessa crittografia di LAN. L'interceptor ChaCha20 e l'envelope firmata
sono byte-identical a LAN. Il
PeerGraphQLServicedel peer non sa quale trasporto abbia consegnato la richiesta. - Nessuna preemption su fallimento del link. Se
buildLinkfallisce, il trasporto lanciaTransportUnavailablee il router ricade su BLE. Non c'è retry dentrosend—AwarePeerLink.buildfa già il proprio loop di retry interno (conMAX_BUILD_ATTEMPTS = 1sul client, di più se il prewarmer ha preparato entrambi i lati).
Percorso di download file (end-to-end) {#file-download-path-end-to-end}
I download file via Aware riusano lo stesso data path dei messaggi di chat, ma usano un client OkHttp separato configurato per lo streaming di file grandi:
Perché un client separato per i download?
Il client di chat (AwareHttpClientFactory.build) ha una
requestTimeoutMillis di 30 s — appropriata per mutation GraphQL ma
catastrofica per un download di file da 100 MB. Il client di download
(buildFileDownload) imposta:
connectTimeoutMillis = 10_000(più lungo dei 5 s della chat, più tollerante per il first-packet lento su un data path fresco)readTimeout = 120 sper read (vs il default implicito di 10 s)requestTimeoutMillis = 120_000(2 minuti — sufficiente per la maggior parte dei file)retryOnConnectionFailure(true)— un read abbandonato a metà download è ritentato invece di fallire l'intero trasferimento
Omette anche l'interceptor ChaCha20. L'endpoint /fs serve byte di file
grezzi (non un'envelope GraphQL firmata), e la PMK L2 (quando presente)
cifra già il link radio. Doppia-cifrare un video da 50 MB con ChaCha20 in
software sprecherebbe CPU e rallenterebbe il trasferimento.
Streaming, non buffering
Come il path BLE, i download Aware streammano il file attraverso un
ByteReadChannel — il file è scritto su un file temp man mano che i byte
arrivano, non buffered in memoria. PeerFileDownloader legge chunk da 8 KB
ed emette eventi di progresso ogni secondo. La stessa pipeline
DownloadedResponse / PeerFileDownloader / DownloadQueue è riusata
attraverso tutti i trasporti — transport-specific solo la sorgente channel.
Prewarming: avvio di Aware innescato da BLE {#prewarming-ble-triggered-aware-startup}
La più grande latenza visibile all'utente nel path Aware è il primo handshake — se entrambi i lati non hanno ancora avviato Aware, il primo messaggio dell'utente deve attendere:
- Attach della sessione Aware locale (~1 s)
- Avvio di publish + subscribe locale (~1 s)
- Avvio di Aware del peer remoto (~2 s via BLE)
- Discovery reciproco (~1 s)
- Handshake NDP (~400 ms)
Sono ~5 secondi prima che il primo byte sia inviato. Per nascondere questa
latenza, PeerTransportPrewarmer gira all'ingresso in ChatPage e
innesca l'avvio di Aware del peer remoto via BLE:
Il duplice ruolo di BLE
BLE serve a due scopi qui:
- Leggere lo stato Aware corrente del peer (economico, nessuna connessione
GATT — il
serviceDatabyte0 della scan response porta i flag Aware). - Innescare il peer per avviare Aware se lo supporta ma non lo sta
attualmente eseguendo. Questo passa attraverso il path
BleTransport.sendregolare — una mutation GraphQLstartAwarecifrata con la chiave ChaCha20 condivisa, consegnata via RPC GATT all'endpoint/peer_graphqldel peer.
Questo è uno dei pochi punti in cui i trasporti cooperano invece di cadere semplicemente l'uno sull'altro: BLE è usato per pre-emptively upgrade la sessione al trasporto Aware più veloce, prima che l'utente anche se ne accorga.
Perché setAwareRunning(true) ottimistico?
La mutation startAware ritorna success non appena il resolver del peer
remoto invoca WifiAwareTransport.start() — ma la sessione Aware non è
ancora effettivamente attached (onAttached scatta asincronamente). PlainApp
marca il peer come awareRunning = true ottimisticamente, perché:
- Se si è avviata davvero, il prossimo
senduserà Aware (veloce). - Se non è successo (ad es. il Wi-Fi del peer è spento), il
buildLinkdel prossimosendfallirà conTransportUnavailablee ricadrà su BLE naturalmente. - Il costo di un falso positivo è un timeout di ~5 s, non un blocco
permanente —
PeerCircuitBreakerregistra il fallimento ma non apre la gamba BLE (BLE si apre solo sui propri fallimenti).
Perché throttle a 30 s?
PeerTransportPrewarmer.prewarm(peerId) registra un timestamp per peer e si
rifiuta di girare di nuovo entro 30 s. Questo perché l'utente naviga avanti e
indietro tra lista chat e pagina chat frequentemente — senza throttling,
ogni navigazione innescerebbe uno scan BLE + mutation startAware, scaricando
la batteria e saturando la radio BLE. La finestra di 30 s è abbastanza corta
da intercettare un peer appena venuto online (ad es. l'utente ha aperto l'app
sul dispositivo remoto) ma abbastanza lunga da evitare re-run spuri.
Modalità di fallimento e il flag fast-skip {#failure-modes--the-fast-skip-flag}
Aware ha più modalità di fallimento di qualsiasi altro trasporto. Il flag
fast-skip isAwareRunning è la singola ottimizzazione più importante
dell'intero modulo — senza di esso, ogni send sprecherebbe 10 s su
buildLink che va in timeout prima di ricadere su BLE.
Il flag isAwareRunning è il perno
Senza questo singolo booleano, ogni send Aware o:
- Tenterebbe sempre
buildLink→ timeout di 10 s su ogni invio a un peer il cui Aware non è in esecuzione. - Saltarebbe sempre Aware → non lo userebbe mai anche quando entrambi i lati lo hanno in esecuzione.
Il flag è aggiornato da due sorgenti, in ordine di autorità:
- Scan response BLE (economico, nessuna connessione GATT) — impostato da
PeerTransportPrewarmer.refreshAwareFlagFromScan. Il peer pubblicizza il proprio stato Aware nel payloadserviceDatadi 9 byte (byte0 bitfield). - Risposta GATT DISCOVER (autoritativa) — impostata da
PairingTransport.scanAndDiscoverquando avviene una discovery completa. Questo sovrascrive l'hint di scan.
Quando false, WifiAwareTransport.send e downloadFile lanciano
TransportUnavailable immediatamente — nessuno scan, nessun handshake,
nessun timeout. Il router ricade su BLE in microsecondi.
Riferimento delle costanti chiave {#key-constants-reference}
| Costante | Valore | Dove | Scopo |
|---|---|---|---|
AwareSession.SERVICE_NAME | "plain-peer" | Discovery | Nome servizio pubblicato & sottoscritto da ogni dispositivo PlainApp |
AwareSession.PEER_HANDLE_MAX_AGE_MS | 30 000 | Cache PeerHandle | Scarta handle stale (la sessione di publish del peer potrebbe essere stata riavviata) |
AwareSession.READY_TIMEOUT_MS | 15 000 | Handshake | Attesa subscriber per la ricevuta ready del publisher |
AwareSession.MSG_HELLO | 0 | Handshake | Subscriber → Publisher message ID |
AwareSession.MSG_READY | 1 | Handshake | Publisher → Subscriber message ID |
AwarePeerLink.MAX_BUILD_ATTEMPTS | 1 | Handshake (solo client) | Singolo tentativo — era 3, ora 1 perché il prewarmer prepara entrambi i lati |
AwarePeerLink.ATTEMPT_TIMEOUT_MS | 5 000 | Handshake | Timeout per-tentativo — era 10 s, dimezzato per accelerare il fallback |
AwarePeerLink.RETRY_DELAY_MS | 500 | Handshake | Ritardo tra tentativi di retry (solo client) |
AwarePeerLink.REQUEST_TIMEOUT_MS | 30 000 | NDP | Timeout di connectivityManager.requestNetwork |
AwareLinkPool.IDLE_TIMEOUT_MS | 60 000 | Pool sweep | Chiude link idle dopo 60 s di inattività |
AwareLinkPool.IDLE_SWEEP_INTERVAL_MS | 10 000 | Pool sweep | Intervallo di sweep |
AwareHttpClientFactory.AWARE_HOST | "plain-aware-peer" | DNS | Hostname sentinel risolto nell'IPv6 del peer da un Dns custom |
build client chat | connectTimeout 5 s, requestTimeout 30 s, interceptor ChaCha20 | ||
buildFileDownload | connectTimeout 10 s, readTimeout 120 s, requestTimeout 120 s, no crypto | ||
PeerTransportPrewarmer.PREWARM_TTL_MS | 30 000 | Prewarm | Throttle per peer |
PeerTransportPrewarmer.BLE_SCAN_TIMEOUT_MS | 15 000 | Prewarm | Timeout scan BLE per refreshAwareFlagFromScan |
PeerCircuitBreaker.WINDOW_MS | 30 000 | Circuit breaker | Durata di apertura dopo soglia |
PeerCircuitBreaker.MAX_FAILURES | 2 | Circuit breaker | Fallimenti entro finestra per aprire |
TempData.httpsPort | 8443 (default) | Server | Porta del publisher pubblicizzata via WifiAwareNetworkSpecifier.setPort |
BleServiceData.AWARE_SUPPORTED | 0x01 | Scan response BLE | Bit che indica che il peer supporta Wi-Fi Aware |
BleServiceData.AWARE_RUNNING | 0x02 | Scan response BLE | Bit che indica che il servizio Aware del peer è attualmente in esecuzione |
Riepilogo dei compromessi di design {#design-trade-offs-recap}
Letture aggiuntive
- Chat Architecture — come
WifiAwareTransportsi inserisce nella catena di fallbackLAN → Aware → BLEe nella pipeline più ampia di send/receive della chat. - BLE Transport — il trasporto di ultima istanza che subentra quando Aware non è disponibile; anche il canale usato dal prewarmer per innescare l'avvio di Aware sul peer remoto.
- Pairing Flow — come viene stabilita la chiave
ChaCha20 condivisa riusata come PMK di Aware, e come i flag di scan
response BLE (
AWARE_SUPPORTED/AWARE_RUNNING) vengono popolati.