L'article couvre le cycle de vie de session Aware (Android uniquement), le
modèle de découverte publish / subscribe, la poignée de main à deux phases
avec séparation des rôles qui synchronise requestNetwork des deux côtés
dans la fenêtre de ~500 ms du framework, le pool de liens par pair avec
balayage d'inactivité, l'astuce IPv6 + DNS personnalisé qui permet à un seul
client OkHttp de servir à la fois LAN et Aware, et le préchauffeur qui
déclenche le démarrage Aware du pair via BLE.
Pour la chaîne de repli plus large, voir Architecture du Chat. Pour le transport BLE qui prend le relais quand Aware est indisponible, voir Transport BLE. Pour la façon dont la clé ChaCha20 partagée réutilisée comme PMK Aware est établie, voir Flux de jumelage.
Table des matières
- Pourquoi Wi-Fi Aware ?
- Où Aware se situe dans la chaîne de repli
- Cycle de vie de session : Attach → Publish + Subscribe
- Découverte et attribution des rôles
- La poignée de main à deux phases (hello + ready)
- NDP requestNetwork — La fenêtre de 500 ms
- Pool de liens par pair et balayage d'inactivité
- Adressage IPv6 et l'astuce DNS
plain-aware-peer - Cryptographie : dérivation PMK et réutilisation ChaCha20
- Chemin d'envoi de message (de bout en bout)
- Chemin de téléchargement de fichier (de bout en bout)
- Préchauffage : démarrage Aware déclenché par BLE
- Modes d'échec et le drapeau de saut rapide
- Référence des constantes clés
- Récapitulatif des compromis de conception
Pourquoi Wi-Fi Aware ? {#why-wi-fi-aware}
Wi-Fi Aware (IEEE 802.11bc, anciennement NAN — Neighbor Awareness Networking) est une certification de la Wi-Fi Alliance qui permet à deux appareils de se découvrir et d'échanger des données sans aucune infrastructure Wi-Fi — pas d'AP, pas de routeur, pas de DHCP. PlainApp l'utilise pour deux scénarios que LAN ne peut pas couvrir :
- SSID/VLAN différents. Un téléphone sur le réseau invité et un laptop sur le VLAN IoT sont tous deux « en ligne » via Wi-Fi mais ne peuvent pas s'atteindre mutuellement par IP. Aware crée un data path direct appareil- à-appareil qui contourne entièrement l'infrastructure.
- Aucune infrastructure du tout. Deux appareils dans la nature avec le Wi-Fi activé mais sans AP peuvent quand même chatter. (BLE couvre aussi ce cas, mais Aware est beaucoup plus rapide — ~10 ms allers-retours vs secondes, et Mo/s vs dizaines de Ko/s.)
Contraintes de plateforme
Wi-Fi Aware est Android uniquement dans PlainApp :
- Android 13 (API 33) est le minimum — les surcharges
WifiAwareNetworkSpecifier.BuilderavecsetPort()etsetPmk()dont PlainApp dépend exigentisTPlus(). - iOS n'expose pas Wi-Fi Aware aux applications tierques. iOS PlainApp
passe directement de LAN à BLE ; l'objet
WifiAwareTransportn'est même pas compilé dans la cible iOS (@RequiresApi(Build.VERSION_CODES.S)+ source set androidMain).
C'est pourquoi PeerTransportRouter.buildList appelle
createWifiAwareTransport() — une fabrique qui renvoie null sur iOS.
Où Aware se situe dans la chaîne de repli {#where-aware-sits-in-the-fallback-chain}
Le PeerTransportRouter de PlainApp est une liste ordonnée. Pour chaque
appel send ou downloadFile, il parcourt la liste et essaie chaque
transport jusqu'à ce que l'un réussisse ; les échecs descendent en cascade.
Pourquoi Aware est-il « au milieu » et pas « en premier » ?
Parce que LAN est presque toujours plus rapide lorsqu'il est disponible. Un saut Wi-Fi même sous-réseau via un AP est un seul échange de trames 802.11 ; un data path Aware ajoute une mise en place NDP (~5 s à la première utilisation) plus un second contexte radio Wi-Fi pour la liaison appareil-à- appareil. Si les deux sont atteignables, LAN gagne en latence et en débit.
À l'inverse, BLE est toujours plus lent — mais il fonctionne dès que les deux appareils sont jumelés. Aware est au milieu : plus rapide que BLE, plus lent que LAN, et uniquement disponible sur les appareils Android 13+ avec le Wi-Fi activé.
Cycle de vie de session : Attach → Publish + Subscribe {#session-lifecycle-attach--publish--subscribe}
Une session Wi-Fi Aware est à l'échelle du processus. Il y a exactement
une WifiAwareSession par appareil ; à l'intérieur, PlainApp fait tourner
une session publish (pour que les pairs puissent nous découvrir) et
une session subscribe (pour que nous puissions découvrir les pairs). Les
deux sont démarrées dès que AwareSession.start() complète le callback
attach.
Pourquoi publish ET subscribe sur le même appareil ?
Le modèle de découverte Wi-Fi Aware est asymétrique : un éditeur publie
un service, un abonné le scanne. Pour rendre la découverte symétrique (les
deux appareils se découvrent mutuellement), PlainApp fait les deux à la
fois. Sans cela, l'appareil A devrait savoir à l'avance s'il est éditeur ou
abonné pour un pair donné — mais les rôles de pair sont déterminés
ultérieurement par comparaison de clientId (voir
Découverte et attribution des rôles).
Publier et s'abonner simultanément signifie que chaque appareil voit le
onServiceDiscovered de l'autre (en tant qu'abonné) ET reçoit les messages
hello de l'autre (en tant qu'éditeur) — les deux directions de la poignée de
main sont toujours disponibles.
Redémarrage automatique sur terminaison
Certaines variantes Android (MIUI en particulier) tuent les sessions Aware
longue durée pour économiser la batterie. PlainApp gère cela dans les
callbacks onSessionTerminated : il met à null la session terminée et
appelle immédiatement publishOwnService / subscribeOwnService à nouveau
sur la WifiAwareSession encore attachée. La session attach elle-même n'est
pas perdue — seule la session de découverte publish/subscribe. Les PeerHandle
d'avant la terminaison deviennent périmés, c'est pourquoi awaitPeerHandle
vérifie l'horodatage discoveredAt et rejette les handles de plus de 30 s.
Découverte et attribution des rôles {#discovery--role-assignment}
Le protocole de data-path Wi-Fi Aware exige qu'un côté agisse comme éditeur (serveur) et l'autre comme abonné (client). Les deux côtés ne peuvent pas simultanément être initiateurs — le framework rejette les requêtes sans contrepartie correspondante.
PlainApp attribue les rôles déterministiquement par pair via une simple comparaison lexicographique des clientIds :
Pourquoi déterministe et non négocié ?
Une approche négociée (par ex. « le MAC le plus bas est serveur »)
exigerait un échange de messages supplémentaire. La comparaison
lexicographique est idempotente, symétrique et sans état : les deux
appareils calculent le même rôle pour la même paire sans aucune
communication. Le clientId est un short UUID de 13 caractères, donc les
égalités (clientId == peer.id) ne se produisent que lors de la comparaison
d'un pair avec lui-même — ce qui n'atteint jamais le transport.
Le rôle détermine deux choses en aval :
- Qui pilote la boucle de réessai. Seul le client réessaie
requestNetwork; le serveur fait exactement une tentative par hello reçu. C'est critique pour la fenêtre de 500 ms (section suivante). - Qui définit le port. L'éditeur appelle
setPort(httpsPort)car c'est lui qui accepte les connexions entrantes sur son port serveur HTTPS. L'abonné ne définit pas de port — il apprend le port du pair depuis leWifiAwareNetworkInfoaprès l'établissement du data path.
La poignée de main à deux phases (hello + ready) {#the-two-phase-handshake-hello--ready}
La partie la plus difficile de la mise en place d'un data-path Wi-Fi Aware
est le timing. Le framework exige que les deux côtés appellent
connectivityManager.requestNetwork dans une fenêtre d'environ 500 ms l'un
de l'autre — si un côté l'appelle avant que l'autre n'ait enregistré sa
requête correspondante, le framework le rejette immédiatement avec
onUnavailable (« releaseRequestAsUnfulfillableByAnyFactory »).
PlainApp résout cela par une poignée de main à deux messages au niveau
application qui tourne au-dessus du canal de messages L2 Aware (la même
API sendMessage utilisée par onServiceDiscovered) :
Pourquoi deux messages (hello + ready) plutôt qu'un seul ?
Le hello seul ne suffit pas à cause de l'asymétrie de direction.
L'abonné peut envoyer le hello dès qu'il découvre l'éditeur (dans
onServiceDiscovered), mais l'éditeur ne peut pas lancer requestNetwork
avant d'avoir le PeerHandle de l'abonné, qu'il n'apprend qu'en recevant le
hello. Donc le hello sert deux objectifs :
- Livrer le PeerHandle de l'abonné à l'éditeur. L'éditeur en a besoin
pour construire le
WifiAwareNetworkSpecifier. - Signaler l'intention de se connecter. Recevoir le hello dit à l'éditeur « l'abonné va faire requestNetwork, donc je devrais aussi ».
L'accusé de réception ready existe pour la direction opposée — pour
dire à l'abonné « l'éditeur a enregistré son requestNetwork ». Sans lui, le
requestNetwork de l'abonné pourrait prendre de l'avance sur celui de
l'éditeur et être rejeté par le framework. L'accusé ready est un
signal non bloquant : l'abonné ne l'attend pas avant d'appeler
requestNetwork (cela ajouterait un aller-retour), mais s'il arrive
pendant que l'abonné est en état IDLE (entre tentatives de réessai),
l'abonné peut réessayer immédiatement sans attendre le délai
RETRY_DELAY_MS.
L'asymétrie de la boucle de réessai
C'est la partie la plus subtile de la conception. Seul l'abonné
réessaie. L'éditeur fait exactement une tentative requestNetwork par
hello reçu. C'est parce que :
- Si les deux côtés réessayaient indépendamment, leurs cycles de réessai
se déphaseraient (durées
delay()différentes, pauses GC différentes), et les deux appelsrequestNetworkchevaucheraient rarement la fenêtre de 500 ms. - La boucle de réessai de l'abonné envoie un nouveau hello à chaque
tentative, ce qui redéclenche le
buildLinkde l'éditeur viapublishHelloListeners. Cela garantit que lerequestNetworkde l'éditeur suit toujours le hello d'environ 50 ms, bien dans la fenêtre de 500 ms.
Ceci est documenté en détail dans
AwarePeerLink.build.
NDP requestNetwork — La fenêtre de 500 ms {#ndp-requestnetwork--the-500-ms-window}
L'appel requestNetwork est l'opération la plus sensible au timing du
transport Aware. Voici ce qui se passe de chaque côté :
Ce que le callback onUnavailable signifie
onUnavailable se déclenche quand le framework rejette le requestNetwork
avant de trouver une requête de pair correspondante. Le PeerHandle lui-
même reste valide — seul l'appairage NDP (Neighbor Discovery Protocol) a
échoué car l'autre côté n'avait pas encore enregistré sa requête. PlainApp
ne délibérément n'appelle pas session.invalidatePeerHandle dans ce cas,
car invalider le handle écarterait le seul signal que
onServiceDiscovered ait jamais été appelé (il se déclenche une fois par
pair par durée de vie de session subscribe). Avec le handle préservé, le
réessai peut le réutiliser au lieu d'attendre une découverte fraîche.
Il en va de même pour le handle côté éditeur depuis onMessageReceived —
l'éditeur conserve l'entrée publishPeerHandles[fromCid] à travers les
tentatives échouées, de sorte que le prochain hello de l'abonné réutilise le
handle en cache au lieu d'être abandonné.
Pool de liens par pair et balayage d'inactivité {#per-peer-link-pool--idle-sweeping}
Chaque pair jumelé obtient son propre objet AwarePeerLink, possédé par
l'AwareLinkPool à l'échelle du processus. Le pool gère les événements de
découverte, la réutilisation des liens et l'éviction des liens inactifs.
Pourquoi pas de construction automatique sur découverte ?
Le pool ne construit pas explicitement de lien lorsque
onServiceDiscovered se déclenche. C'est une décision critique : un café
animé pourrait avoir 100 appareils PlainApp publiant tous le service
« plain-peer ». Si chaque découverte déclenchait un requestNetwork, le
framework serait inondé de tentatives de mise en place NDP et la radio Wi-Fi
serait saturée.
Au lieu de cela, le pool enregistre uniquement le PeerHandle et attend l'un de ces événements :
- L'utilisateur local envoie un message →
WifiAwareTransport.send→pool.buildLink(peer)(déclenchement côté émetteur). - Le pair distant envoie un hello →
onPublishHelloReceived→buildLink(peer)(déclenchement côté récepteur). - Le pair distant envoie un ready →
onSubscribeReadyReceived→buildLink(peer)(déclenchement côté récepteur).
Ainsi, les liens ne sont construits que pour les pairs avec lesquels l'utilisateur échange réellement des messages — pas chaque appareil PlainApp à portée radio.
Balayage d'inactivité
Toutes les 10 secondes, le pool parcourt tous les liens et ferme ceux dont
lastActiveAt date de plus de 60 secondes. Chaque send et downloadFile
appelle link.touch() pour rafraîchir l'horodatage. Cela récupère le contexte
radio Wi-Fi et le pool de connexions OkHttp pour les pairs avec lesquels
l'utilisateur a cessé de chatter — important car Android limite le nombre de
data paths Aware simultanés à environ 4–10 (selon l'appareil).
Adressage IPv6 et l'astuce DNS plain-aware-peer {#ipv6-addressing--the-plain-aware-peer-dns-trick}
Les data paths Wi-Fi Aware utilisent IPv6 link-local uniquement. Il n'y a
ni IPv4, ni serveur DNS, ni DHCP. L'adresse IPv6 du pair est livrée via le
champ WifiAwareNetworkInfo.peerIpv6Addr dans onCapabilitiesChanged — une
adresse fe80::... qui n'a de sens que sur l'interface réseau Aware.
PlainApp doit envoyer des requêtes HTTPS à cette adresse, mais l'analyse
d'URL https:// d'OkHttp refuse les littéraux IPv6 bruts dans un nom d'hôte
(https://[fe80::abcd]:8443/ fonctionne, mais le router via un résolveur
Dns personnalisé est plus propre). L'astuce :
Pourquoi un nom d'hôte sentinel ?
L'alternative — passer le littéral IPv6 directement dans l'URL —
exigerait que chaque site d'appel connaisse l'adresse link-local. En
utilisant un nom d'hôte sentinel, la construction de l'URL est identique pour
LAN et Aware : les deux produisent une URL https://<host>:<port>/peer_graphql
valide qu'OkHttp peut analyser. La seule différence est l'implémentation
Dns liée au client — LAN utilise le DNS système, Aware utilise
awareDns(peerIpv6) qui renvoie l'adresse link-local en cache pour le nom
d'hôte sentinel et retombe sur Dns.SYSTEM pour tout le reste.
Pourquoi network.socketFactory ?
L'objet Network d'Android représente une interface réseau spécifique (en
l'occurrence, le data path Aware). En appelant network.socketFactory et en
le passant à la config socketFactory d'OkHttp, nous forçons toutes les
sockets TCP à être créées sur l'interface Aware — pas l'interface Wi-Fi
ou cellulaire par défaut. Sans cela, l'OS routerait la requête via le réseau
par défaut, où l'IPv6 link-local est injoignable, et la requête échouerait
avec ENETUNREACH.
Cryptographie : dérivation PMK et réutilisation ChaCha20 {#cryptography-pmk-derivation--chacha20-reuse}
Wi-Fi Aware supporte une PMK (Pairwise Master Key) optionnelle pour le data path. Quand elle est définie, le lien L2 lui-même est chiffré avec cette PMK — la radio Wi-Fi gère le chiffrement, nul besoin de crypto au niveau application.
PlainApp dérive la PMK de la même clé partagée ChaCha20 que
LanTransport et BleTransport utilisent pour le chiffrement au niveau
application :
Pourquoi tronquer à 32 octets ?
La PMK Wi-Fi Aware doit faire exactement 32 octets (256 bits). La clé
partagée ChaCha20 issue du jumelage fait aussi 32 octets dans le cas normal,
donc la branche raw.size == 32 est le chemin courant. La repli
troncature/padding gère le cas (théorique) où la clé aurait été stockée plus
courte — remplir de zéros pour atteindre 32 octets est une mesure défensive,
pas quelque chose qui arrive en pratique avec des pairs correctement jumelés.
L'enveloppe signée est identique à LAN
Comme createCryptoHttpClient est la même fabrique que celle utilisée par
LanTransport, la crypto L7 sur Aware est identique octet pour octet à
LAN. Le PeerGraphQLService côté serveur ne sait pas (et n'a pas à le
savoir) quel transport a livré la requête — il voit simplement une charge
utile GraphQL signée et chiffrée et la déchiffre avec la clé partagée du
pair. C'est le principe « une base de code, plusieurs transports » documenté
dans Architecture du Chat.
Chemin d'envoi de message (de bout en bout) {#message-send-path-end-to-end}
En assemblant tout — ce qui se passe quand un message de chat est envoyé via Wi-Fi Aware :
Choix de conception notables
- Réutilisation de connexion. Contrairement à
BleTransport, qui démonte la connexion GATT après chaque requête,WifiAwareTransportréutilise le data path Aware pour autant de requêtes que l'utilisateur fait dans la fenêtre d'inactivité de 60 s. La première requête paie la poignée de main de ~400 ms ; les requêtes suivantes font ~10 ms allers-retours. - Même crypto que LAN. L'intercepteur ChaCha20 et l'enveloppe signée
sont identiques octet pour octet à LAN. Le
PeerGraphQLServicedu pair ne sait pas quel transport a livré la requête. - Pas de préemption sur échec de lien. Si
buildLinkéchoue, le transport lèveTransportUnavailableet le routeur passe à BLE. Il n'y a pas de réessai danssend—AwarePeerLink.buildfait déjà sa propre boucle de réessai interne (avecMAX_BUILD_ATTEMPTS = 1côté client, plus si le préchauffeur a préparé les deux côtés).
Chemin de téléchargement de fichier (de bout en bout) {#file-download-path-end-to-end}
Les téléchargements de fichiers via Aware réutilisent le même data path que les messages de chat, mais utilisent un client OkHttp séparé configuré pour le streaming de gros fichiers :
Pourquoi un client séparé pour les téléchargements ?
Le client de chat (AwareHttpClientFactory.build) a un
requestTimeoutMillis de 30 s — approprié pour des mutations GraphQL mais
catastrophique pour un téléchargement de fichier de 100 Mo. Le client de
téléchargement (buildFileDownload) définit :
connectTimeoutMillis = 10_000(plus long que les 5 s du chat, plus tolérant pour un premier paquet lent sur un data path frais)readTimeout = 120 spar lecture (vs la valeur par défaut implicite de 10 s)requestTimeoutMillis = 120_000(2 minutes — suffisant pour la plupart des fichiers)retryOnConnectionFailure(true)— une lecture interrompue en milieu de téléchargement est réessayée au lieu de faire échouer tout le transfert
Il omet aussi l'intercepteur ChaCha20. L'endpoint /fs sert des octets
de fichier bruts (pas une enveloppe GraphQL signée), et la PMK L2 (lorsqu'elle
est présente) chiffre déjà le lien radio. Double-chiffrer une vidéo de 50 Mo
avec ChaCha20 en logiciel gaspillerait du CPU et ralentirait le transfert.
Streaming, pas de mise en mémoire tampon
Comme le chemin BLE, les téléchargements Aware streament le fichier à travers
un ByteReadChannel — le fichier est écrit dans un fichier temporaire à
mesure que les octets arrivent, pas mis en mémoire tampon. Le
PeerFileDownloader lit des morceaux de 8 Ko et émet des événements de
progression chaque seconde. Le même pipeline
DownloadedResponse / PeerFileDownloader / DownloadQueue est réutilisé
à travers tous les transports — seul le channel source est spécifique au
transport.
Préchauffage : démarrage Aware déclenché par BLE {#prewarming-ble-triggered-aware-startup}
La plus grande latence visible par l'utilisateur dans le chemin Aware est la première poignée de main — si les deux côtés n'ont pas encore démarré Aware, le premier message de l'utilisateur doit attendre :
- Attach de la session Aware locale (~1 s)
- Démarrage local publish + subscribe (~1 s)
- Démarrage Aware du pair distant (~2 s via BLE)
- Découverte mutuelle (~1 s)
- Poignée de main NDP (~400 ms)
Cela fait ~5 secondes avant l'envoi du premier octet. Pour masquer cette
latence, PeerTransportPrewarmer s'exécute à l'entrée de ChatPage et
déclenche le démarrage Aware du pair distant via BLE :
Le double rôle de BLE
BLE sert deux objectifs ici :
- Lire l'état Aware courant du pair (bon marché, pas de connexion GATT
— le
serviceDatabyte0 de la scan response porte les drapeaux Aware). - Déclencher le démarrage Aware du pair s'il le supporte mais ne le fait
pas tourner actuellement. Cela passe par le chemin habituel
BleTransport.send— une mutation GraphQLstartAwarechiffrée avec la clé ChaCha20 partagée, livrée via RPC GATT à l'endpoint/peer_graphqldu pair.
C'est l'un des rares endroits où les transports coopèrent plutôt que de se contenter de se replier : BLE est utilisé pour améliorer préventivement la session vers le transport Aware plus rapide, avant même que l'utilisateur ne s'en rende compte.
Pourquoi un setAwareRunning(true) optimiste ?
La mutation startAware renvoie le succès dès que le résolveur du pair
distant invoque WifiAwareTransport.start() — mais la session Aware n'est
pas encore réellement attachée (onAttached se déclenche de façon
asynchrone). PlainApp marque le pair comme awareRunning = true
optimistiquement, parce que :
- Si elle a vraiment démarré, le prochain
sendutilisera Aware (rapide). - Si ce n'est pas le cas (par ex. le Wi-Fi du pair est éteint), le
buildLinkdu prochainsendéchouera avecTransportUnavailableet retombera sur BLE naturellement. - Le coût d'un faux positif est un délai d'attente de ~5 s, pas un blocage
permanent —
PeerCircuitBreakerenregistre l'échec mais n'ouvre pas la jambe BLE (BLE ne s'ouvre que sur ses propres échecs).
Pourquoi une limitation à 30 s ?
PeerTransportPrewarmer.prewarm(peerId) enregistre un horodatage par pair
et refuse de se réexécuter dans les 30 s. C'est parce que l'utilisateur
navigue fréquemment entre la liste de chat et la page de chat — sans
limitation, chaque navigation déclencherait un scan BLE + une mutation
startAware, drainant la batterie et spamme la radio BLE. La fenêtre de 30 s
est assez courte pour rattraper un pair qui vient d'arriver en ligne (par ex.
l'utilisateur a ouvert l'appareil sur l'appareil distant) mais assez longue
pour éviter les réexécutions intempestives.
Modes d'échec et le drapeau de saut rapide {#failure-modes--the-fast-skip-flag}
Aware a plus de modes d'échec que tout autre transport. Le drapeau de saut
rapide isAwareRunning est la plus importante optimisation de tout le
module — sans lui, chaque send gaspillerait 10 s sur un buildLink
expirant avant de retomber sur BLE.
Le drapeau isAwareRunning est le pivot
Sans ce simple booléen, chaque send Aware soit :
- Toujours tenterait
buildLink→ délai d'attente de 10 s à chaque envoi vers un pair dont Aware ne tourne pas. - Toujours sauterait Aware → ne l'utiliserait jamais même quand les deux côtés le font tourner.
Le drapeau est rafraîchi depuis deux sources, par ordre d'autorité :
- Scan response BLE (bon marché, pas de connexion GATT) — défini par
PeerTransportPrewarmer.refreshAwareFlagFromScan. Le pair publie son état Aware dans la charge utileserviceDatade 9 octets (byte0 bitfield). - Réponse DISCOVER GATT (autorisée) — définie par
PairingTransport.scanAndDiscoverlorsqu'une découverte complète se fait. Elle écrase l'indice de scan.
Quand il est faux, WifiAwareTransport.send et downloadFile lèvent
TransportUnavailable immédiatement — pas de scan, pas de poignée de
main, pas de délai d'attente. Le routeur passe à BLE en microsecondes.
Référence des constantes clés {#key-constants-reference}
| Constante | Valeur | Où | Rôle |
|---|---|---|---|
AwareSession.SERVICE_NAME | "plain-peer" | Découverte | Nom de service publié et abonné par chaque appareil PlainApp |
AwareSession.PEER_HANDLE_MAX_AGE_MS | 30 000 | Cache PeerHandle | Rejeter les handles périmés (la session publish du pair a peut-être été redémarrée) |
AwareSession.READY_TIMEOUT_MS | 15 000 | Poignée de main | Attente de l'abonné pour l'accusé ready de l'éditeur |
AwareSession.MSG_HELLO | 0 | Poignée de main | ID du message Abonné → Éditeur |
AwareSession.MSG_READY | 1 | Poignée de main | ID du message Éditeur → Abonné |
AwarePeerLink.MAX_BUILD_ATTEMPTS | 1 | Poignée de main (client uniquement) | Une seule tentative — était 3, maintenant 1 car le préchauffeur prépare les deux côtés |
AwarePeerLink.ATTEMPT_TIMEOUT_MS | 5 000 | Poignée de main | Délai par tentative — était 10 s, divisé par 2 pour accélérer le repli |
AwarePeerLink.RETRY_DELAY_MS | 500 | Poignée de main | Délai entre les tentatives de réessai (client uniquement) |
AwarePeerLink.REQUEST_TIMEOUT_MS | 30 000 | NDP | Délai de connectivityManager.requestNetwork |
AwareLinkPool.IDLE_TIMEOUT_MS | 60 000 | Balayage du pool | Fermer les liens inactifs après 60 s d'inactivité |
AwareLinkPool.IDLE_SWEEP_INTERVAL_MS | 10 000 | Balayage du pool | Intervalle de balayage |
AwareHttpClientFactory.AWARE_HOST | "plain-aware-peer" | DNS | Nom d'hôte sentinel résolu en IPv6 du pair par un Dns personnalisé |
build client chat | connectTimeout 5 s, requestTimeout 30 s, intercepteur ChaCha20 | ||
buildFileDownload | connectTimeout 10 s, readTimeout 120 s, requestTimeout 120 s, pas de crypto | ||
PeerTransportPrewarmer.PREWARM_TTL_MS | 30 000 | Préchauffage | Limitation par pair |
PeerTransportPrewarmer.BLE_SCAN_TIMEOUT_MS | 15 000 | Préchauffage | Délai de scan BLE pour refreshAwareFlagFromScan |
PeerCircuitBreaker.WINDOW_MS | 30 000 | Disjoncteur | Durée d'ouverture après seuil |
PeerCircuitBreaker.MAX_FAILURES | 2 | Disjoncteur | Échecs dans la fenêtre pour ouvrir |
TempData.httpsPort | 8443 (défaut) | Serveur | Port de l'éditeur annoncé via WifiAwareNetworkSpecifier.setPort |
BleServiceData.AWARE_SUPPORTED | 0x01 | Scan response BLE | Bit indiquant que le pair supporte Wi-Fi Aware |
BleServiceData.AWARE_RUNNING | 0x02 | Scan response BLE | Bit indiquant que le service Aware du pair tourne actuellement |
Récapitulatif des compromis de conception {#design-trade-offs-recap}
Pour aller plus loin
- Architecture du Chat — comment
WifiAwareTransports'intègre dans la chaîne de repliLAN → Aware → BLEet le pipeline plus large d'envoi/réception de chat. - Transport BLE — le transport de dernier recours qui prend le relais quand Aware est indisponible ; aussi le canal utilisé par le préchauffeur pour déclencher le démarrage Aware sur le pair distant.
- Flux de jumelage — comment la clé ChaCha20
partagée réutilisée comme PMK Aware est établie, et comment les drapeaux
de scan response BLE (
AWARE_SUPPORTED/AWARE_RUNNING) sont peuplés. pour les drapeauxisAwareRunning/isAwareSupporteden mémoire.