Terug naar blog
Transport19 min read

Wi-Fi Aware-transportontwerp — Neighbor Discovery en data-paden

Dit artikel legt uit hoe PlainApp Wi-Fi Aware (NAN — Neighbor Awareness Networking) gebruikt als de middelste laag van zijn peer-transport-fallback-chain, tussen LAN (same-subnet HTTPS) en BLE (last-resort GATT RPC). Wi-Fi Aware is wat twee PlainApp-apparaten laat communiceren wanneer ze op verschillende SSID's zitten, gast versus IoT-VLAN's, of helemaal geen Wi-Fi-infrastructuur — zonder ooit een IP-adres van een DHCP-server nodig te hebben.

Het artikel behandelt de Android-only Aware-sessie-levenscyclus, het publish / subscribe-ontdekkingsmodel, de twee-fase-rolverdeel-handshake die requestNetwork aan beide kanten synchroniseert binnen het ~500 ms- venster van het framework, de per-peer-link-pool met idle-sweeping, de IPv6 + aangepaste-DNS-truc die een enkele OkHttp-client zowel LAN als Aware laat bedienen, en de prewarmer die peer-Aware-startup via BLE triggert.

Voor de bredere fallback-chain, zie Chatarchitectuur. Voor het BLE-transport dat overneemt wanneer Aware onbeschikbaar is, zie BLE-transport. Voor hoe de gedeelde ChaCha20-sleutel die wordt hergebruikt als de Aware-PMK wordt opgebouwd, zie het Koppelingsproces.

Inhoudsopgave

Waarom Wi-Fi Aware? {#why-wi-fi-aware}

Wi-Fi Aware (IEEE 802.11bc, voorheen NAN — Neighbor Awareness Networking) is een Wi-Fi Alliance-certificering die twee apparaten in staat stelt elkaar te ontdekken en data uit te wisselen zonder enige Wi-Fi-infrastructuur — geen AP, geen router, geen DHCP. PlainApp gebruikt het voor twee scenario's die LAN niet kan dekken:

  • Verschillende SSID's / VLAN's. Een telefoon op het gastnetwerk en een laptop op het IoT-VLAN zijn beide "online" via Wi-Fi maar kunnen elkaars IP niet bereiken. Aware creëert een direct apparaat-tot-apparaat-data-pad dat de infrastructuur volledig omzeilt.
  • Helemaal geen infrastructuur. Twee apparaten in de wildernis met Wi-Fi aan maar zonder AP kunnen nog steeds chatten. (BLE dekt dit ook, maar Aware is veel sneller — ~10 ms round trips versus seconden, en MB/s versus tientallen KB/s.)

Diagram 1
1

Platformbeperkingen

Wi-Fi Aware is alleen Android in PlainApp:

  • Android 13 (API 33) is het minimum — de WifiAwareNetworkSpecifier.Builder-overloads met setPort() en setPmk() waarvan PlainApp afhankelijk is, vereisen isTPlus().
  • iOS ontsluit Wi-Fi Aware niet aan third-party apps. iOS-PlainApp valt direct van LAN naar BLE; het WifiAwareTransport-object wordt niet eens gecompileerd in de iOS-target (@RequiresApi(Build.VERSION_CODES.S)
    • androidMain-source-set).

Daarom roept PeerTransportRouter.buildListcreateWifiAwareTransport() aan — een factory die null retourneert op iOS.

Waar Aware zit in de fallback-chain {#where-aware-sits-in-the-fallback-chain}

PlainApp's PeerTransportRouter is een geordende lijst. Voor elke send- of downloadFile-aanroep loopt het de lijst af en probeert elk transport totdat één slaagt; storingen cascaderen naar beneden.

Diagram 2
2

Waarom is Aware "het midden" en niet "de eerste"?

Omdat LAN bijna altijd sneller is wanneer beschikbaar. Een same-subnet Wi-Fi-hop via een AP is een enkele 802.11-frame-uitwisseling; een Aware-data-pad voegt een NDP-setup toe (~5 s bij eerste gebruik) plus een tweede Wi-Fi-radi-context voor de apparaat-tot-apparaat-verbinding. Als beide bereikbaar zijn, wint LAN op latentie en doorvoer.

Omgekeerd is BLE altijd trager — maar het werkt wanneer beide apparaten maar gekoppeld zijn. Aware zit in het midden: sneller dan BLE, trager dan LAN, en alleen beschikbaar op Android 13+-apparaten met Wi-Fi aan.

Sessie-levenscyclus: Attach → Publish + Subscribe {#session-lifecycle-attach--publish--subscribe}

Een Wi-Fi Aware-sessie is procesbreed. Er is precies één WifiAwareSession per apparaat; daarin draait PlainApp één publish-sessie (zodat peers ons kunnen ontdekken) en één subscribe-sessie (zodat we peers kunnen ontdekken). Beide worden gestart zodra AwareSession.start() de attach-callback voltooit.

Diagram 3
3

Waarom publish EN subscribe op hetzelfde apparaat?

Het Wi-Fi Aware-ontdekkingsmodel is asymmetrisch: een publisher adverteert een service, een subscriber scant ernaar. Om ontdekking symmetrisch te maken (beide apparaten ontdekken elkaar), doet PlainApp beide tegelijk. Zonder dit zou apparaat A vooraf moeten weten of het de publisher of de subscriber is voor een bepaalde peer — maar peer-rollen worden later bepaald door clientId-vergelijking (zie Ontdekking en roltoewijzing).

Tegelijkertijd publiceren en abonneren betekent dat elk apparaat elkaars onServiceDiscovered ziet (als subscriber) EN elkaars hello-berichten ontvangt (als publisher) — beide richtingen van de handshake zijn altijd beschikbaar.

Auto-restart bij beëindiging

Sommige Android-varianten (met name MIUI) beëindigen langlopende Aware-sessies om batterij te besparen. PlainApp handelt dit af in de onSessionTerminated-callbacks: het zet de beëindigde sessie op null en roept onmiddellijk opnieuw publishOwnService / subscribeOwnService aan op de nog-verbonden WifiAwareSession. De attach-sessie zelf gaat niet verloren — alleen de publish/subscribe-ontdekkingssessie. Peer-handles van vóór de beëindiging worden stale, daarom controleert awaitPeerHandle de discoveredAt-timestamp en verwijdert handles ouder dan 30 s.

Ontdekking en roltoewijzing {#discovery--role-assignment}

Het Wi-Fi Aware-data-path-protocol vereist dat de ene kant optreedt als publisher (server) en de andere als subscriber (client). Beide kanten kunnen niet gelijktijdig de initiator zijn — het framework wijst verzoeken zonder een passende counterpart af.

PlainApp wijst rollen deterministisch per peer toe met een eenvoudige lexicografische vergelijking van clientIds:

Diagram 4
4

Waarom deterministisch en niet onderhandeld?

Een onderhandelde aanpak (bijv. "lagere MAC is de server") zou een extra bericht-uitwisseling vereisen. De lexicografische vergelijking is idempotent, symmetrisch en stateless: beide apparaten berekenen dezelfde rol voor hetzelfde paar zonder enige communicatie. De clientId is een 13-tekens short UUID, dus gelijkspel (clientId == peer.id) treedt alleen op bij vergelijking van een peer met zichzelf — wat nooit het transport bereikt.

De rol bepaalt downstream twee dingen:

  1. Wie de hertry-loop aandrijft. Alleen de client probeert requestNetwork opnieuw; de server doet precies één poging per ontvangen hello. Dit is kritiek voor het 500 ms-venster (volgende sectie).
  2. Wie de poort instelt. De publisher roept setPort(httpsPort) aan omdat het degene is die inkomende verbindingen accepteert op zijn HTTPS-serverpoort. De subscriber stelt geen poort in — hij leert de poort van de peer uit de WifiAwareNetworkInfo nadat het data-pad is opgezet.

De twee-fase-handshake (hello + ready) {#the-two-phase-handshake-hello--ready}

Het moeilijkste deel van Wi-Fi Aware-data-path-setup is timing. Het framework vereist dat beide kanten connectivityManager.requestNetwork binnen ongeveer 500 ms van elkaar aanroepen — als de ene kant het aanroept voordat de andere zijn passend verzoek heeft geregistreerd, wijst het framework het onmiddellijk af met onUnavailable ("releaseRequestAsUnfulfillableByAnyFactory").

PlainApp lost dit op met een twee-bericht applicatie-laag-handshake die draait bovenop het Aware L2-berichtkanaal (dezelfde sendMessage- API die door onServiceDiscovered wordt gebruikt):

Diagram 5
5

Waarom twee berichten (hello + ready) in plaats van slechts één?

De hello alleen is niet genoeg vanwege richtingsasymmetrie. De subscriber kan hello verzenden zodra hij de publisher ontdekt (in onServiceDiscovered), maar de publisher kan niet requestNetwork starten totdat hij de PeerHandle van de subscriber heeft, die hij pas leert door de hello te ontvangen. Dus de hello dient twee doelen:

  1. De PeerHandle van de subscriber aan de publisher leveren. De publisher heeft deze nodig om de WifiAwareNetworkSpecifier te bouwen.
  2. Intentie om te verbinden signaleren. Het ontvangen van de hello vertelt de publisher "de subscriber staat op het punt requestNetwork te doen, dus ik ook."

De ready-bevestiging bestaat voor de tegenovergestelde richting — om de subscriber te vertellen "de publisher heeft zijn requestNetwork geregistreerd." Zonder dit zou de requestNetwork van de subscriber voor die van de publisher kunnen uitrennen en door het framework worden afgewezen. De ready-bevestiging is een non-blocking signaal: de subscriber wacht er niet op voordat hij requestNetwork aanroept (dat zou een round-trip toevoegen), maar als het aankomt terwijl de subscriber in IDLE-state is (tussen hertry-pogingen), kan de subscriber onmiddellijk opnieuw proberen zonder op de RETRY_DELAY_MS-gap te wachten.

De asymmetrie van de hertry-loop

Dit is het meest subtiele deel van het ontwerp. Alleen de subscriber doet hertries. De publisher doet precies één requestNetwork-poging per ontvangen hello. Dit komt omdat:

  • Als beide kanten onafhankelijk hertries zouden doen, zouden hun hertry-cycli uit fase drijven (verschillende delay()-duren, verschillende GC-pauzes), en de twee requestNetwork-aanroepen zouden zelden binnen het 500 ms-venster overlappen.
  • De hertry-loop van de subscriber stuurt bij elke poging een verse hello, wat de buildLink van de publisher opnieuw triggert via publishHelloListeners. Dit garandeert dat de requestNetwork van de publisher altijd op ~50 ms na de hello volgt, ruim binnen het 500 ms-venster.

Dit is in detail gedocumenteerd in AwarePeerLink.build.

NDP requestNetwork — Het 500 ms-venster {#ndp-requestnetwork--the-500-ms-window}

De requestNetwork-aanroep is de meest timing-gevoelige operatie in het Aware-transport. Hier is wat er aan elke kant gebeurt:

Diagram 6
6

Wat de onUnavailable-callback betekent

onUnavailable vuurt wanneer het framework het requestNetwork afwijst voordat een passend peer-verzoek wordt gevonden. De PeerHandle zelf is nog steeds geldig — alleen de NDP (Neighbor Discovery Protocol)- paring faalde omdat de andere kant nog niet had geregistreerd. PlainApp roept in dit geval bewust nietsession.invalidatePeerHandle aan, omdat het invalidaten van de handle het enige signaal zou weggooien dat onServiceDiscovered ooit is aangeroepen (het vuurt één keer per peer per levensduur van de subscribe-sessie). Met de handle behouden kan de hertry deze hergebruiken in plaats van wachten op een verse ontdekking.

Hetzelfde geldt voor de publisher-zijde-handle van onMessageReceived — de publisher behoudt de publishPeerHandles[fromCid]-entry over mislukte pogingen, zodat de volgende hello van de subscriber de gecachede handle hergebruikt in plaats van te worden gedropt.

Elke gekoppelde peer krijgt zijn eigen AwarePeerLink-object, eigendom van de procesbrede AwareLinkPool. De pool behandelt ontdekkingsevenementen, link-hergebruik en idle-verwijdering.

Diagram 7
7

Waarom niet auto-builden bij ontdekking?

De pool bouwt expliciet geen link wanneer onServiceDiscovered vuurt. Dit is een kritieke beslissing: een drukke koffietent kan 100 PlainApp-apparaten hebben die allemaal de "plain-peer"-service publiceren. Als elke ontdekking een requestNetwork zou triggeren, zou het framework worden overspoeld met NDP-setup-pogingen en zou de Wi-Fi-radio worden verzadigd.

In plaats daarvan noteert de pool alleen de PeerHandle en wacht op één van:

  1. De lokale gebruiker verzendt een berichtWifiAwareTransport.sendpool.buildLink(peer) (verzender-zijde-trigger).
  2. De remote peer stuurt een helloonPublishHelloReceivedbuildLink(peer) (ontvanger-zijde-trigger).
  3. De remote peer stuurt een readyonSubscribeReadyReceivedbuildLink(peer) (ontvanger-zijde-trigger).

Zo worden links alleen gebouwd voor peers waarmee de gebruiker daadwerkelijk berichten uitwisselt — niet elk PlainApp-apparaat in radiobereik.

Idle-sweep

Elke 10 seconden loopt de pool alle links langs en sluit elke link waarvan lastActiveAt ouder is dan 60 seconden. Elke send en downloadFile roept link.touch() aan om de timestamp te verversen. Dit maakt de Wi-Fi-radi-context en OkHttp-connectie-pool vrij voor peers waarmee de gebruiker is gestopt chatten — belangrijk omdat Android het aantal gelijktijdige Aware-data-paden beperkt tot ongeveer 4–10 (apparaatafhankelijk).

IPv6-adressering en de plain-aware-peer-DNS-truc {#ipv6-addressing--the-plain-aware-peer-dns-trick}

Wi-Fi Aware-data-paden gebruiken alleen link-local IPv6. Er is geen IPv4, geen DNS-server, geen DHCP. Het IPv6-adres van de peer wordt geleverd via het WifiAwareNetworkInfo.peerIpv6Addr-veld in onCapabilitiesChanged — een fe80::...-adres dat alleen betekenis heeft op de Aware-netwerkinterface.

PlainApp moet HTTPS-verzoeken naar dit adres sturen, maar de https://-URL-parsing van OkHttp weigert raw IPv6-literals in een hostnaam (https://[fe80::abcd]:8443/ werkt, maar het via een aangepaste Dns-resolver leiden is schoner). De truc:

Diagram 8
8

Waarom een sentinel-hostnaam?

Het alternatief — de IPv6-literal direct in de URL doorgeven — zou vereisen dat elke call-site op de hoogte is van het link-local-adres. Door een sentinel-hostnaam te gebruiken is de URL-constructie identiek voor LAN en Aware: beide produceren een geldige https://<host>:<port>/peer_graphql-URL die OkHttp kan parsen. Het enige verschil is de aan de client gebonden Dns-implementatie — LAN gebruikt de systeem-DNS, Aware gebruikt awareDns(peerIpv6) die het gecacheerde link-local-adres voor de sentinel-hostnaam retourneert en voor al het andere naar Dns.SYSTEM doorvalt.

Waarom network.socketFactory?

Het Network-object van Android vertegenwoordigt een specifieke netwerkinterface (in dit geval het Aware-data-pad). Door network.socketFactory aan te roepen en het door te geven aan de socketFactory-config van OkHttp, forceren we dat alle TCP-sockets op de Aware-interface worden gecreëerd — niet de standaard Wi-Fi- of cellulaire interface. Zonder dit zou het OS het verzoek via het standaardnetwerk routeren, waar de link-local IPv6 onbereikbaar is, en zou het verzoek falen met ENETUNREACH.

Cryptografie: PMK-afleiding en ChaCha20-hergebruik {#cryptography-pmk-derivation--chacha20-reuse}

Wi-Fi Aware ondersteunt een optionele PMK (Pairwise Master Key) voor het data-pad. Wanneer ingesteld, is de L2-link zelf versleuteld met die PMK — de Wi-Fi-radio handelt versleuteling af, geen applicatie-laag-crypto nodig.

PlainApp leidt de PMK af van dezelfde gedeelde ChaCha20-sleutel die LanTransport en BleTransport gebruiken voor applicatie-laag-versleuteling:

Diagram 9
9

Waarom afkappen tot 32 bytes?

De Wi-Fi Aware-PMK moet exact 32 bytes (256 bits) zijn. De gedeelde ChaCha20-sleutel uit koppeling is in het normale geval ook 32 bytes, dus de raw.size == 32-tak is het algemene pad. De afkap/opvul-fallback handelt het (theoretische) geval af waarin de sleutel korter was opgeslagen — opvullen met nullen tot 32 bytes is een defensieve maatregel, geen iets dat in de praktijk voorkomt bij correct gekoppelde peers.

De ondertekende envelope is identiek aan LAN

Omdat createCryptoHttpClient dezelfde factory is die door LanTransport wordt gebruikt, is de L7-crypto op Aware byte-voor-byte identiek aan LAN. De PeerGraphQLService aan server-zijde weet niet (of kan het niet schelen) welk transport het verzoek heeft afgeleverd — hij ziet slechts een ondertekende, versleutelde GraphQL-payload en ontcijfert het met de gedeelde sleutel van de peer. Dit is het "één codebase, vele transports"- principe gedocumenteerd in Chatarchitectuur.

Verzendpad voor berichten (end-to-end) {#message-send-path-end-to-end}

Alles samenvoegend — wat gebeurt er wanneer een chatbericht via Wi-Fi Aware wordt verzonden:

Diagram 10
10

Opmerkelijke ontwerpkeuzes

  • Hergebruik van verbindingen. In tegenstelling tot BleTransport, dat de GATT-verbinding na elk verzoek afbreekt, hergebruikt WifiAwareTransport het Aware-data-pad voor zoveel verzoeken als de gebruiker doet binnen het 60 s-idle-venster. Het eerste verzoek betaalt de ~400 ms-handshake; volgende verzoeken zijn ~10 ms round-trips.
  • Dezelfde crypto als LAN. De ChaCha20-interceptor en ondertekende envelope zijn byte-identiek aan LAN. De PeerGraphQLService van de peer weet niet welk transport het verzoek heeft afgeleverd.
  • Geen preemption bij link-fout. Als buildLink faalt, gooit het transport TransportUnavailable en valt de router door naar BLE. Er is geen hertry binnen sendAwarePeerLink.build doet al zijn eigen interne hertry-loop (met MAX_BUILD_ATTEMPTS = 1 aan de client-kant, meer als de prewarmer beide kanten heeft geprimed).

Downloadpad voor bestanden (end-to-end) {#file-download-path-end-to-end}

Bestandsdownloads via Aware hergebruiken hetzelfde data-pad als chatberichten, maar gebruiken een aparte OkHttp-client die is geconfigureerd voor het streamen van grote bestanden:

Diagram 11
11

Waarom een aparte client voor downloads?

De chat-client (AwareHttpClientFactory.build) heeft een 30 s-requestTimeoutMillis — passend voor GraphQL-mutations maar catastrofaal voor een 100 MB-bestandsdownload. De download-client (buildFileDownload) stelt in:

  • connectTimeoutMillis = 10_000 (langer dan de 5 s van chat, meer tolerant voor traag first-packet op een vers data-pad)
  • readTimeout = 120 s per read (versus de impliciete standaard van 10 s)
  • requestTimeoutMillis = 120_000 (2 minuten — genoeg voor de meeste bestanden)
  • retryOnConnectionFailure(true) — een verloren read midden in de download wordt opnieuw geprobeerd in plaats van de hele overdracht te laten falen

Het laat ook de ChaCha20-interceptor achterwege. Het /fs-endpoint serveert ruwe bestands-bytes (geen ondertekende GraphQL-envelope), en de L2-PMK (indien aanwezig) versleutelt al de radiolink. Dubbel versleutelen van een 50 MB-video met ChaCha20 in software zou CPU verspillen en de overdracht vertragen.

Streamen, niet bufferen

Zoals het BLE-pad, streamen Aware-downloads het bestand door een ByteReadChannel — het bestand wordt naar een temp-bestand geschreven zoals bytes aankomen, niet in memory gebufferd. PeerFileDownloader leest 8 KB-chunks en emit elk seconde voortgangsevenementen. Dezelfde DownloadedResponse / PeerFileDownloader / DownloadQueue-pijplijn wordt hergebruikt over alle transports — alleen de channel-bron is transport-specifiek.

Prewarming: BLE-getriggerde Aware-startup {#prewarming-ble-triggered-aware-startup}

De grootste voor de gebruiker zichtbare latentie in het Aware-pad is de eerste handshake — als beide kanten Aware nog niet hebben gestart, moet het eerste bericht van de gebruiker wachten op:

  1. Lokale Aware-sessie-attach (~1 s)
  2. Lokale publish + subscribe-start (~1 s)
  3. Aware-startup van de remote peer (~2 s via BLE)
  4. Wederzijdse ontdekking (~1 s)
  5. NDP-handshake (~400 ms)

Dat is ~5 seconden voordat de eerste byte wordt verzonden. Om deze latentie te verbergen, draait PeerTransportPrewarmer bij binnenkomst op ChatPage en triggert de Aware-startup van de remote peer via BLE:

Diagram 12
12

De dubbele rol van BLE

BLE dient hier twee doelen:

  1. De huidige Aware-state van de peer lezen (goedkoop, geen GATT-connect — de serviceData byte0 van de scanrespons vervoert de Aware-vlaggen).
  2. De peer triggeren om Aware te starten als het het ondersteunt maar momenteel niet draait. Dit gaat via het reguliere BleTransport.send-pad — een startAware-GraphQL-mutation versleuteld met de gedeelde ChaCha20-sleutel, afgeleverd via GATT-RPC naar het /peer_graphql-endpoint van de peer.

Dit is een van de weinige plaatsen waar de transports samenwerken in plaats van alleen maar terug te vallen: BLE wordt gebruikt om de sessie preemptief te upgraden naar het snellere Aware-transport, voordat de gebruiker het überhaupt merkt.

Waarom optimistisch setAwareRunning(true)?

De startAware-mutation retourneert succes zodra de resolver van de remote peer WifiAwareTransport.start() aanroept — maar de Aware-sessie is nog niet echt verbonden (onAttached vuurt asynchroon). PlainApp markeert de peer optimistisch als awareRunning = true, omdat:

  • Als het daadwerkelijk startte, zal de volgende send Aware gebruiken (snel).
  • Als het niet zo is (bijv. Wi-Fi van de peer staat uit), zal de buildLink van de volgende send falen met TransportUnavailable en van nature naar BLE terugvallen.
  • De kosten van een false positive zijn één ~5 s-timeout, geen permanente blokkade — PeerCircuitBreaker noteert de fout maar opent de BLE-leg niet (BLE opent alleen bij zijn eigen fouten).

Waarom throttelen tot 30 s?

PeerTransportPrewarmer.prewarm(peerId) noteert een timestamp per peer en weigert binnen 30 s opnieuw te draaien. Dit komt omdat de gebruiker veelvuldig heen en weer navigeert tussen chat-lijst en chat-pagina — zonder throttling zou elke navigatie een BLE-scan + startAware-mutation triggern, wat batterij zou verbruiken en de BLE-radio zou spammen. Het 30 s-venster is kort genoeg om een peer die net online is gekomen te vangen (bijv. gebruiker opende de app op het remote apparaat) maar lang genoeg om spurieuze her-runs te vermijden.

Foutmodi en de fast-skip-vlag {#failure-modes--the-fast-skip-flag}

Aware heeft meer foutmodi dan enig ander transport. De isAwareRunning-fast-skip-vlag is de belangrijkste optimalisatie in de hele module — zonder deze zou elke send 10 s verspillen aan buildLink-timeouts voordat naar BLE wordt teruggevallen.

Diagram 13
13

De isAwareRunning-vlag is de spil

Zonder deze enkele boolean zou elke Aware-send ofwel:

  • Altijd buildLink proberen → 10 s-timeout bij elke send naar een peer wiens Aware niet draait.
  • Altijd Aware overslaan → het nooit gebruiken, zelfs niet wanneer beide kanten het draaien.

De vlag wordt ververst vanuit twee bronnen, in volgorde van autoriteit:

  1. BLE-scanrespons (goedkoop, geen GATT-connect) — ingesteld door PeerTransportPrewarmer.refreshAwareFlagFromScan. De peer adverteert zijn Aware-state in de 9-byte serviceData-payload (byte0-bitfield).
  2. GATT DISCOVER-antwoord (autoritatief) — ingesteld door PairingTransport.scanAndDiscover wanneer een volledige ontdekking plaatsvindt. Dit overschrijft de scan-hint.

Wanneer onwaar, gooien WifiAwareTransport.send en downloadFile onmiddellijk TransportUnavailable — geen scan, geen handshake, geen timeout. De router valt in microseconden door naar BLE.

Referentie van sleutelconstanten {#key-constants-reference}

ConstanteWaardeWaarDoel
AwareSession.SERVICE_NAME"plain-peer"OntdekkingServicenaam gepubliceerd & geabonneerd door elk PlainApp-apparaat
AwareSession.PEER_HANDLE_MAX_AGE_MS30 000PeerHandle-cacheVerwijder stale handles (publish-sessie van peer kan zijn herstart)
AwareSession.READY_TIMEOUT_MS15 000HandshakeSubscriber-wachttijd op ready-bevestiging van publisher
AwareSession.MSG_HELLO0HandshakeSubscriber → Publisher-bericht-ID
AwareSession.MSG_READY1HandshakePublisher → Subscriber-bericht-ID
AwarePeerLink.MAX_BUILD_ATTEMPTS1Handshake (alleen client)Eén poging — was 3, nu 1 omdat prewarmer beide kanten primed
AwarePeerLink.ATTEMPT_TIMEOUT_MS5 000HandshakePer-poging-timeout — was 10 s, gehalveerd om fallback te versnellen
AwarePeerLink.RETRY_DELAY_MS500HandshakeVertraging tussen hertry-pogingen (alleen client)
AwarePeerLink.REQUEST_TIMEOUT_MS30 000NDPconnectivityManager.requestNetwork-timeout
AwareLinkPool.IDLE_TIMEOUT_MS60 000Pool-sweepSluit idle links na 60 s inactiviteit
AwareLinkPool.IDLE_SWEEP_INTERVAL_MS10 000Pool-sweepSweep-interval
AwareHttpClientFactory.AWARE_HOST"plain-aware-peer"DNSSentinel-hostnaam opgelost naar peer-IPv6 door aangepaste Dns
build chat-clientconnectTimeout 5 s, requestTimeout 30 s, ChaCha20-interceptor
buildFileDownloadconnectTimeout 10 s, readTimeout 120 s, requestTimeout 120 s, geen crypto
PeerTransportPrewarmer.PREWARM_TTL_MS30 000PrewarmThrottle per peer
PeerTransportPrewarmer.BLE_SCAN_TIMEOUT_MS15 000PrewarmBLE-scan-timeout voor refreshAwareFlagFromScan
PeerCircuitBreaker.WINDOW_MS30 000Circuit-breakerOpen-duur na drempel
PeerCircuitBreaker.MAX_FAILURES2Circuit-breakerFouten binnen venster om te openen
TempData.httpsPort8443 (standaard)ServerPoort van publisher geadverteerd via WifiAwareNetworkSpecifier.setPort
BleServiceData.AWARE_SUPPORTED0x01BLE-scanresponsBit die aangeeft dat peer Wi-Fi Aware ondersteunt
BleServiceData.AWARE_RUNNING0x02BLE-scanresponsBit die aangeeft dat de Aware-service van peer momenteel draait

Samenvatting van ontwerpafwegingen {#design-trade-offs-recap}

Diagram 14
14

Verder lezen

  • Chatarchitectuur — hoe WifiAwareTransport past in de LAN → Aware → BLE-fallback-chain en de bredere chat-verzend/ontvang-pijplijn.
  • BLE-transport — het last-resort-transport dat overneemt wanneer Aware onbeschikbaar is; ook het kanaal dat door de prewarmer wordt gebruikt om Aware-startup op de remote peer te triggeren.
  • Koppelingsproces — hoe de gedeelde ChaCha20-sleutel die als de Aware-PMK wordt hergebruikt, wordt opgebouwd, en hoe de BLE-scanrespons-vlaggen (AWARE_SUPPORTED / AWARE_RUNNING) worden gevuld.