இக்கட்டுரை Android-மட்டும் Aware அமர்வு வாழ்க்கைச்சுழற்சி, publish / subscribe
கண்டுபிடிப்பு மாதிரி, ஃப்ரேம்வொர்க்கின் ~500 ms சாளரத்திற்குள் இரு தரப்பிலும்
requestNetwork-ஐ ஒருங்கிணைக்கும் இரண்டு-கட்ட பங்கு-பிரிப்பு handshake, ஒருங்கிணைந்த
sweeping-உடன் பியர்-வாரி இணைப்பு குளம், ஒற்றை OkHttp கிளையன்ட் LAN மற்றும் Aware
இரண்டையும் பணியாற்ற அனுமதிக்கும் IPv6 + தனிப்பயன்-DNS தந்திரம், மற்றும் BLE வழியாக
பியர் Aware தொடக்கத்தைத் தூண்டும் prewarmer ஆகியவற்றை உள்ளடக்கியது.
பரந்த fallback சங்கிலிக்கு, அரட்டைக் கட்டமைப்பு-ஐப் பார்க்கவும். Aware கிடைக்காதபோது ஏற்றுக்கொள்ளும் BLE போக்குவரத்திற்கு, BLE போக்குவரத்து-ஐப் பார்க்கவும். Aware PMK-ஆக மீண்டும் பயன்படுத்தப்படும் பகிரப்பட்ட ChaCha20 விசை எப்படி நிறுவப்படுகிறது என்பதற்கு பெயரிங் பாய்வு-ஐப் பார்க்கவும்.
பொருளடக்கம்
- Wi-Fi Aware ஏன்?
- Fallback சங்கிலியில் Aware எங்கே அமர்ந்திருக்கிறது
- அமர்வு வாழ்க்கைச்சுழற்சி: Attach → Publish + Subscribe
- கண்டுபிடிப்பு & பங்கு ஒதுக்கீடு
- இரண்டு-கட்ட handshake (hello + ready)
- NDP requestNetwork — 500 ms சாளரம்
- பியர்-வாரி இணைப்பு குளம் & ஒருங்கிணைந்த Sweeping
- IPv6 முகவரியிடல் &
plain-aware-peerDNS தந்திரம் - மறையாக்கவியல்: PMK வழிப்பாடு & ChaCha20 மறுபயன்பாடு
- செய்தி அனுப்பல் பாதை (முழுமையான)
- கோப்பு பதிவிறக்கப் பாதை (முழுமையான)
- Prewarming: BLE-தூண்டப்பட்ட Aware தொடக்கம்
- தோல்வி முறைகள் & விரைவு-தவிர் கொடி
- முக்கிய மாறிலிகள் குறிப்பு
- வடிவமைப்பு பரிமாற்றங்கள் சுருக்கம்
Wi-Fi Aware ஏன்? {#why-wi-fi-aware}
Wi-Fi Aware (IEEE 802.11bc, முன்பு NAN — Neighbor Awareness Networking) என்பது இரண்டு சாதனங்கள் எந்த Wi-Fi உள்கட்டமைப்பும் இல்லாமலேயே ஒன்றையொன்று கண்டுபிடித்து தரவைப் பரிமாற அனுமதிக்கும் ஒரு Wi-Fi Alliance சான்றிதழ் — AP இல்லை, ரவுட்டர் இல்லை, DHCP இல்லை. PlainApp அதை LAN மூட முடியாத இரண்டு சூழ்நிலைகளுக்குப் பயன்படுத்துகிறது:
- வெவ்வேறு SSID-கள் / VLAN-கள். guest நெட்வொர்க்கில் ஒரு தொலைபேசி மற்றும் IoT VLAN-இல் ஒரு மடிக்கணினி இரண்டும் Wi-Fi வழியாக "ஆன்லைனில்" இருந்தாலும் ஒன்றையொன்றின் IP-ஐ அடைய முடியாது. Aware உள்கட்டமைப்பைத் தவிர்த்து ஒரு நேரடி சாதனத்திலிருந்து-சாதனம் தரவுப் பாதையை உருவாக்குகிறது.
- உள்கட்டமைப்பே இல்லை. Wi-Fi ஆன் ஆக இருந்தாலும் AP இல்லாமல் காட்டில் இரண்டு சாதனங்கள் இன்னும் அரட்டையாடலாம். (BLE-உம் இதை மூடுகிறது, ஆனால் Aware மிக வேகமானது — விநாடிகளுக்கு பதிலாக ~10 ms ரவுண்ட் ட்ரிப்கள், மற்றும் பத்துகள் KB/s-க்கு பதிலாக MB/s.)
தள கட்டுப்பாடுகள்
Wi-Fi Aware PlainApp-இல் Android-மட்டும்:
- Android 13 (API 33) குறைந்தபட்சம் — PlainApp சார்ந்திருக்கும்
setPort()மற்றும்setPmk()overloads உடன்WifiAwareNetworkSpecifier.BuilderisTPlus()-ஐ வேண்டும். - iOS மூன்றாம் தரப்பு செயலிகளுக்கு Wi-Fi Aware-ஐ வெளிப்படுத்துவதில்லை. iOS PlainApp
LAN-இலிருந்து நேரடியாக BLE-க்கு விழுகிறது;
WifiAwareTransportobject iOS இலக்காக ஒருபோதும் தொகுக்கப்படுவதில்லை (@RequiresApi(Build.VERSION_CODES.S)+ androidMain மூலத் தொகுப்பு).
இதுதான் PeerTransportRouter.buildList createWifiAwareTransport()-ஐ அழைப்பதற்கான
காரணம் — iOS-இல் null-ஐத் திருப்பி அனுப்பும் ஒரு factory.
Fallback சங்கிலியில் Aware எங்கே அமர்ந்திருக்கிறது {#where-aware-sits-in-the-fallback-chain}
PlainApp-ன் PeerTransportRouter ஒரு வரிசையான பட்டியல். ஒவ்வொரு send அல்லது
downloadFile அழைப்பிற்கும், அது பட்டியலை நடந்து ஒன்று வெற்றிபெறும் வரை ஒவ்வொரு
போக்குவரத்தையும் முயற்சிக்கிறது; தோல்விகள் கீழே நீர்வீழ்ச்சி செய்கின்றன.
Aware "நடுவில்" தான் ஏன், "முதலில்" அல்ல?
ஏனெனில் LAN கிடைக்கும்போது கிட்டத்தட்ட எப்போதும் வேகமானது. AP வழியாக ஒரு அதே-சப்நெட் Wi-Fi hop என்பது ஒரு ஒற்றை 802.11 சட்டக பரிமாற்றம்; ஒரு Aware தரவுப் பாதை ஒரு NDP அமைப்பு (முதல் பயன்பாட்டில் ~5 வி) மற்றும் சாதனத்திலிருந்து-சாதனம் இணைப்புக்கான இரண்டாவது Wi-Fi ரேடியோ context-ஐச் சேர்க்கிறது. இரண்டும் அடையக்கூடியவை என்றால், LAN தாமதம் மற்றும் செயல்திறனில் வெல்கிறது.
மாறாக, BLE எப்போதும் மெதுவானது — ஆனால் இரண்டு சாதனங்களும் பெயர் செய்யப்பட்டால் வேலை செய்கிறது. Aware நடுவில் உள்ளது: BLE-விட வேகமானது, LAN-விட மெதுவானது, மற்றும் Wi-Fi ஆன் உடன் Android 13+ சாதனங்களில் மட்டுமே கிடைக்கிறது.
அமர்வு வாழ்க்கைச்சுழற்சி: Attach → Publish + Subscribe {#session-lifecycle-attach--publish--subscribe}
ஒரு Wi-Fi Aware அமர்வு செயல்முறை-அளவு. ஒரு சாதனத்திற்கு சரியாக ஒரு
WifiAwareSession; அதற்குள், PlainApp ஒரு publish அமர்வு (பியர்கள் எங்களைக்
கண்டுபிடிக்க) மற்றும் ஒரு subscribe அமர்வு (நாங்கள் பியர்களைக் கண்டுபிடிக்க)
இரண்டையும் இயக்குகிறது. AwareSession.start() attach கால்பேக்கை முடிக்கும்
கணத்தில் இரண்டும் தொடங்கப்படுகின்றன.
ஏன் ஒரே சாதனத்தில் publish மற்றும் subscribe?
Wi-Fi Aware கண்டுபிடிப்பு மாதிரி சமச்சீரற்றது: ஒரு publisher ஒரு சேவையை விளம்பரப்படுத்துகிறது,
ஒரு subscriber அதைத் தேடுகிறது. கண்டுபிடிப்பை சமச்சீராக்க (இரு சாதனங்களும் ஒன்றையொன்று
கண்டுபிடிக்க), PlainApp இரண்டையும் ஒரே நேரத்தில் செய்கிறது. இல்லாவிட்டால்,
A சாதனம் ஒரு குறிப்பிட்ட பியருக்கு அது publisher அல்லது subscriber என்பதை முன்கூட்டியே
தெரிந்துகொள்ள வேண்டும் — ஆனால் பியர் பங்குகள் பின்னர் clientId ஒப்பீட்டால் தீர்மானிக்கப்படுகின்றன
(கண்டுபிடிப்பு & பங்கு ஒதுக்கீடு-ஐப் பார்க்கவும்).
ஒரே நேரத்தில் publish மற்றும் subscribe செய்வது என்பது ஒவ்வொரு சாதனமும் மறுபக்கத்தின்
onServiceDiscovered-ஐ (subscriber ஆக) AND மறுபக்கத்தின் hello செய்திகளைப் பெறுகிறது
(publisher ஆக) — handshake-ன் இரு திசைகளும் எப்போதும் கிடைக்கின்றன.
முடிவடைப்பில் தானியங்கு-மறுதொடக்கம்
சில Android மாறுபாடுகள் (குறிப்பாக MIUI) பேட்டரியைச் சேமிக்க நீண்ட-கால Aware
அமர்வுகளைக் கொல்கின்றன. PlainApp இதை onSessionTerminated கால்பேக்குகளில் கையாளுகிறது:
அது முடிக்கப்பட்ட அமர்வை null செய்து, இன்னும்-இணைக்கப்பட்ட WifiAwareSession-இல்
உடனடியாக publishOwnService / subscribeOwnService-ஐ மீண்டும் அழைக்கிறது. Attach
அமர்வு இழக்கப்படவில்லை — publish/subscribe கண்டுபிடிப்பு அமர்வு மட்டுமே. முடிவடைப்பிற்கு
முந்தைய பியர் handles பழையதாகின்றன, இதனால் awaitPeerHandle discoveredAt நேரமுத்திரையைச்
சரிபார்த்து, 30 வி-க்கு பழைய handles-ஐ நீக்குகிறது.
கண்டுபிடிப்பு & பங்கு ஒதுக்கீடு {#discovery--role-assignment}
Wi-Fi Aware தரவு-பாதை நெறிமுறை ஒரு பக்கம் publisher (சேவையகம்) ஆகவும் மற்றொன்று subscriber (கிளையன்ட்) ஆகவும் செயல்பட வேண்டும். இரு தரப்பும் ஒரே நேரத்தில் initiator ஆக முடியாது — ஃப்ரேம்வொர்க் பொருந்தக்கூடிய counterpart இல்லாத கோரிக்கைகளை நிராகரிக்கிறது.
PlainApp clientIds-ன் எளிய lexicographic ஒப்பீட்டைப் பயன்படுத்தி பியர்-வாரியாக நிர்ணயமாக பங்குகளை ஒதுக்குகிறது:
நிர்ணயமானது ஏன், பேச்சுவார்த்தை செய்யப்பட்டது அல்ல?
ஒரு பேச்சுவார்த்தை அணுகுமுறை (உ.ம். "குறைந்த MAC சேவையகம்") ஒரு கூடுதல் செய்திப்
பரிமாற்றம் தேவைப்படும். Lexicographic ஒப்பீடு idempotent, சமச்சீர், மற்றும் stateless:
இரு சாதனங்களும் எந்தத் தகவல்தொடர்பும் இல்லாமல் அதே ஜோடிக்கு அதே பங்கைக் கணக்கிடுகின்றன.
clientId ஒரு 13-எழுத்து short UUID, எனவே ties (clientId == peer.id) ஒரு பியரை அதனுடனேயே
ஒப்பிடும்போது மட்டுமே நிகழும் — இது ஒருபோதும் போக்குவரத்தை அடைவதில்லை.
பங்கு இரண்டு விஷயங்களை downstream தீர்மானிக்கிறது:
- யார் மறுமுயற்சி வளையத்தை இயக்குகிறார்கள். கிளையன்ட் மட்டுமே
requestNetwork-ஐ மறுமுயற்சி செய்கிறது; சேவையகம் ஒவ்வொரு hello-க்கும் சரியாக ஒரு முயற்சி செய்கிறது. இது 500 ms சாளரத்திற்கு முக்கியம் (அடுத்த பிரிவு). - யார் port-ஐ அமைக்கிறார்கள். Publisher தனது HTTPS சேவையக port-இல் உள்வரும்
இணைப்புகளை ஏற்பதால்
setPort(httpsPort)-ஐ அழைக்கிறது. Subscriber port-ஐ அமைக்காது — தரவுப் பாதை நிறுவப்பட்ட பிறகுWifiAwareNetworkInfo-இலிருந்து பியரின் port-ஐக் கற்றுக்கொள்கிறது.
இரண்டு-கட்ட handshake (hello + ready) {#the-two-phase-handshake-hello--ready}
Wi-Fi Aware தரவு-பாதை அமைப்பின் கடினமான பகுதி timing. ஃப்ரேம்வொர்க் இரு தரப்பையும்
ஒன்றையொன்றிடமிருந்து தோராயமாக 500 ms-க்குள் connectivityManager.requestNetwork-ஐ
அழைக்க வேண்டும் — ஒரு தரப்பு மறு தரப்பு அதன் பொருந்தக்கூடிய கோரிக்கையைப் பதிவுசெய்வதற்கு
முன்பு அதை அழைத்தால், ஃப்ரேம்வொர்க் onUnavailable ("releaseRequestAsUnfulfillableByAnyFactory")
உடன் உடனடியாக நிராகரிக்கிறது.
PlainApp இதை Aware L2 செய்திச் சேனலின் மேல் இயங்கும் (onServiceDiscovered-ஆல்
பயன்படுத்தப்படும் அதே sendMessage API) ஒரு இரண்டு-செய்தி பயன்பாட்டு-அடுக்கு handshake-உடன்
தீர்க்கிறது:
ஏன் இரண்டு செய்திகள் (hello + ready), ஒன்று அல்ல?
hello மட்டும் போதாது, ஏனெனில் திசை சமச்சீரின்மை. Subscriber publisher-ஐக்
கண்டுபிடிக்கும் கணத்தில் (onServiceDiscovered-இல்) hello-ஐ அனுப்ப முடியும், ஆனால்
publisher subscriber-ன் PeerHandle-ஐப் பெறும் வரை requestNetwork-ஐத் தொடங்க முடியாது,
அது hello-ஐப் பெறுவதன் மூலம் மட்டுமே கற்றுக்கொள்கிறது. எனவே hello இரண்டு நோக்கங்களைக்
கொண்டுள்ளது:
- subscriber-ன் PeerHandle-ஐ publisher-க்கு வழங்குதல். Publisher-க்கு அது
WifiAwareNetworkSpecifier-ஐ உருவாக்கத் தேவை. - இணைக்க நோக்கத்தை சமிக்ஞை செய்தல். hello-ஐப் பெறுவது publisher-க்கு "subscriber requestNetwork செய்யப்போகிறார், எனவே நானும் செய்ய வேண்டும்" எனக் கூறுகிறது.
ready ரசீது எதிர் திசைக்கு இருக்கிறது — subscriber-க்கு "publisher அவரது
requestNetwork-ஐப் பதிவுசெய்துவிட்டார்" எனக் கூற. இது இல்லாவிட்டால், subscriber-ன்
requestNetwork publisher-ன் request-ஐ விட முன்னே ஓடி, ஃப்ரேம்வொர்க்கால் நிராகரிக்கப்படலாம்.
ready ரசீது ஒரு non-blocking சமிக்ஞை: subscriber requestNetwork-ஐ அழைப்பதற்கு
முன்பு அதற்காக காத்திருப்பதில்லை (அது ஒரு ரவுண்ட் ட்ரிப்பைச் சேர்க்கும்), ஆனால் அது
subscriber IDLE நிலையில் (மறுமுயற்சி முயற்சிகளுக்கு இடையில்) இருக்கும்போது வந்தால்,
subscriber RETRY_DELAY_MS இடைவெளிக்குக் காத்திருக்காமல் உடனடியாக மறுமுயற்சி செய்யலாம்.
மறுமுயற்சி-வளைய சமச்சீரின்மை
இது வடிவமைப்பின் மிகச் சூக்ஷ்மமான பகுதி. subscriber மட்டுமே மறுமுயற்சி செய்கிறது.
Publisher ஒவ்வொரு hello-க்கும் சரியாக ஒரு requestNetwork முயற்சியை மேற்கொள்கிறது.
இதற்குக் காரணம்:
- இரு தரப்பும் சுயாதீனமாக மறுமுயற்சி செய்தால், அவற்றின் மறுமுயற்சி சுழற்சிகள்
கட்டத்திற்கு வெளியே நகரும் (வெவ்வேறு
delay()காலஅளவுகள், வெவ்வேறு GC இடைநிறுத்தங்கள்), மற்றும் இரண்டுrequestNetworkஅழைப்புகளும் 500 ms சாளரத்திற்குள் அரிதாகவே ஒன்றாக இருக்கும். - subscriber-ன் மறுமுயற்சி வளையம் ஒவ்வொரு முயற்சியிலும் ஒரு புதிய hello-ஐ அனுப்புகிறது,
இது
publishHelloListenersவழியாக publisher-ன்buildLink-ஐ மறு-தூண்டுகிறது. இது publisher-ன்requestNetworkஎப்போதும் hello-ஐத் தொடர்ந்து ~50 ms-க்குப் பிறகு வருவதை உத்தரவாதம் செய்கிறது, 500 ms சாளரத்திற்குள் நன்றாக.
இது
AwarePeerLink.build-இல்
விரிவாக ஆவணப்படுத்தப்பட்டுள்ளது.
NDP requestNetwork — 500 ms சாளரம் {#ndp-requestnetwork--the-500-ms-window}
requestNetwork அழைப்பு Aware போக்குவரத்தில் மிக டைமிங்-உணர்திறன் கொண்ட செயல்பாடு.
ஒவ்வொரு பக்கத்திலும் என்ன நிகழ்கிறது:
onUnavailable கால்பேக்கின் பொருள்
onUnavailable ஃப்ரேம்வொர்க் பொருந்தக்கூடிய பியர் request-ஐக் கண்டுபிடிப்பதற்கு முன்பு
requestNetwork-ஐ நிராகரிக்கும்போது இயங்குகிறது. PeerHandle இன்னும் செல்லுபடியாகும் —
NDP (Neighbor Discovery Protocol) pairing மட்டுமே தோல்வியடைந்தது, ஏனெனில் மறு தரப்பு
இன்னும் பதிவுசெய்யவில்லை. PlainApp இந்த வழக்கில் session.invalidatePeerHandle-ஐ
வேண்டுமென்றே அழைப்பதில்லை, ஏனெனில் handle-ஐ invalidate செய்வது onServiceDiscovered
ஒருபோதும் அழைக்கப்பட்டதற்கான ஒரே சமிக்ஞையை (ஒவ்வொரு subscribe அமர்வு வாழ்நாளிலும்
ஒரு பியருக்கு ஒருமுறை இயங்குகிறது) நீக்கிவிடும். Handle பாதுகாக்கப்பட்டால், மறுமுயற்சி
ஒரு புதிய கண்டுபிடிப்புக்குக் காத்திருக்காமல் அதை மீண்டும் பயன்படுத்தலாம்.
அதே onMessageReceived-இலிருந்து publisher-பக்க handle-க்கும் பொருந்தும் — publisher
தோல்வியடைந்த முயற்சிகளிலும் publishPeerHandles[fromCid] உள்ளீட்டை வைத்திருக்கிறது,
எனவே subscriber-ன் அடுத்த hello கேஷ் செய்யப்பட்ட handle-ஐ மீண்டும் பயன்படுத்துகிறது,
கைவிடப்படுவதற்கு பதிலாக.
பியர்-வாரி இணைப்பு குளம் & ஒருங்கிணைந்த Sweeping {#per-peer-link-pool--idle-sweeping}
ஒவ்வொரு பெயர் செய்த பியருக்கும் அதன் சொந்த AwarePeerLink object உள்ளது, செயல்முறை-அளவு
AwareLinkPool-ஆல் வைத்திருக்கப்படுகிறது. குளம் கண்டுபிடிப்பு நிகழ்வுகள், இணைப்பு மறுபயன்பாடு,
மற்றும் ஒருங்கிணைந்த eviction ஆகியவற்றைக் கையாளுகிறது.
கண்டுபிடிப்பில் ஏன் auto-build இல்லை?
குளம் வெளிப்படையாக onServiceDiscovered இயங்கும்போது ஒரு இணைப்பை உருவாக்குவதில்லை.
இது ஒரு முக்கிய முடிவு: ஒரு பிஸியான காபி கடையில் 100 PlainApp சாதனங்கள் அனைத்தும்
"plain-peer" சேவையை வெளியிடும். ஒவ்வொரு கண்டுபிடிப்பும் ஒரு requestNetwork-ஐத்
தூண்டினால், ஃப்ரேம்வொர்க் NDP அமைப்பு முயற்சிகளால் நிரம்பி, Wi-Fi ரேடியோ saturated ஆகிவிடும்.
அதற்குப் பதிலாக, குளம் PeerHandle-ஐ மட்டுமே பதிவு செய்து, பின்வருபவற்றில் ஒன்றிற்காக காத்திருக்கிறது:
- உள்ளக பயனர் ஒரு செய்தியை அனுப்புகிறார் →
WifiAwareTransport.send→pool.buildLink(peer)(அனுப்புநர்-பக்க தூண்டல்). - தொலைநிலை பியர் ஒரு hello-ஐ அனுப்புகிறது →
onPublishHelloReceived→buildLink(peer)(பெறுநர்-பக்க தூண்டல்). - தொலைநிலை பியர் ஒரு ready-ஐ அனுப்புகிறது →
onSubscribeReadyReceived→buildLink(peer)(பெறுநர்-பக்க தூண்டல்).
இவ்வாறு, இணைப்புகள் பயனர் உண்மையில் செய்திகளைப் பரிமாறும் பியர்களுக்கு மட்டுமே உருவாக்கப்படுகின்றன — ரேடியோ வரம்பில் உள்ள ஒவ்வொரு PlainApp சாதனத்திற்கும் அல்ல.
ஒருங்கிணைந்த sweep
ஒவ்வொரு 10 விநாடிகளுக்கும், குளம் எல்லா இணைப்புகளையும் நடந்து, lastActiveAt 60
விநாடிகளுக்கு பழையதாக இருக்கும் எதையும் மூடுகிறது. ஒவ்வொரு send மற்றும்
downloadFile-உம் நேரமுத்திரையைப் புதுப்பிக்க link.touch()-ஐ அழைக்கிறது. இது பயனர் அரட்டையடித்து நிறுத்திய பியர்களுக்கான Wi-Fi ரேடியோ context மற்றும் OkHttp இணைப்பு குளத்தை
மீட்டெடுக்கிறது — முக்கியம், ஏனெனில் Android ஒரே நேர Aware தரவுப் பாதைகளின் எண்ணிக்கையை
தோராயமாக 4–10-ஆக கட்டுப்படுத்துகிறது (சாதனத்தைப் பொறுத்து).
IPv6 முகவரியிடல் & plain-aware-peer DNS தந்திரம் {#ipv6-addressing--the-plain-aware-peer-dns-trick}
Wi-Fi Aware தரவுப் பாதைகள் link-local IPv6 மட்டும் பயன்படுத்துகின்றன. IPv4 இல்லை,
DNS சேவையகம் இல்லை, DHCP இல்லை. பியரின் IPv6 முகவரி onCapabilitiesChanged-இல்
WifiAwareNetworkInfo.peerIpv6Addr புலம் வழியாக வழங்கப்படுகிறது — ஒரு fe80::...
முகவரி, அது Aware நெட்வொர்க் இடைமுகத்தில் மட்டுமே அர்த்தமுள்ளது.
PlainApp-க்கு இந்த முகவரிக்கு HTTPS கோரிக்கைகளை அனுப்ப வேண்டும், ஆனால் OkHttp-ன்
https:// URL parsing ஒரு hostname-இல் raw IPv6 literal-ஐ நிராகரிக்கிறது
(https://[fe80::abcd]:8443/ வேலை செய்யும், ஆனால் அதை தனிப்பயன் Dns resolver
வழியாக ரூட் செய்வது தூய்மையானது). தந்திரம்:
ஏன் ஒரு sentinel hostname?
மாற்று — IPv6 literal-ஐ URL-இல் நேரடியாக அனுப்புவது — ஒவ்வொரு call site-உம் link-local
முகவரியைத் தெரிந்துகொள்ள வேண்டும். ஒரு sentinel hostname-ஐப் பயன்படுத்துவதன் மூலம், URL
கட்டமைப்பு LAN மற்றும் Aware இரண்டிற்கும் ஒரே மாதிரி: இரண்டும் OkHttp parse செய்யக்கூடிய
செல்லுபடியாகும் https://<host>:<port>/peer_graphql URL-ஐ உருவாக்குகின்றன. ஒரே
வித்தியாசம் கிளையன்டுடன் பிணைக்கப்பட்ட Dns செயலாக்கம் — LAN சிஸ்டம் DNS-ஐப் பயன்படுத்துகிறது,
Aware sentinel hostname-க்கு கேஷ் செய்யப்பட்ட link-local முகவரியைத் திருப்பி அனுப்பும்
மற்றும் வேறெதற்கும் Dns.SYSTEM-க்கு விழும் awareDns(peerIpv6)-ஐப் பயன்படுத்துகிறது.
ஏன் network.socketFactory?
Android-ன் Network object ஒரு குறிப்பிட்ட நெட்வொர்க் இடைமுகத்தை (இந்த வழக்கில்,
Aware தரவுப் பாதை) குறிக்கிறது. network.socketFactory-ஐ அழைத்து அதை OkHttp-ன்
socketFactory config-க்கு அனுப்புவதன் மூலம், எல்லா TCP sockets-உம் Aware இடைமுகத்தில்
உருவாக்கப்பட கட்டாயப்படுத்துகிறோம் — இயல்புநிலை Wi-Fi அல்லது cellular இடைமுகம் அல்ல.
இது இல்லாவிட்டால், OS கோரிக்கையை இயல்புநிலை நெட்வொர்க் வழியாக ரூட் செய்யும், அங்கு
link-local IPv6 அடைய முடியாதது, மேலும் கோரிக்கை ENETUNREACH உடன் தோல்வியடையும்.
மறையாக்கவியல்: PMK வழிப்பாடு & ChaCha20 மறுபயன்பாடு {#cryptography-pmk-derivation--chacha20-reuse}
Wi-Fi Aware தரவுப் பாதைக்கு ஒரு optional PMK (Pairwise Master Key)-ஐ ஆதரிக்கிறது. அமைக்கப்பட்டால், L2 link அந்த PMK-உடன் மறைகுறியாக்கப்படுகிறது — Wi-Fi ரேடியோ மறைகுறியாக்கத்தைக் கையாளுகிறது, பயன்பாட்டு-அடுக்கு மறைகுறியாக்கம் தேவையில்லை.
PlainApp PMK-ஐ LanTransport மற்றும் BleTransport பயன்பாட்டு-அடுக்கு மறைகுறியாக்கத்திற்கு
பயன்படுத்தும் அதே ChaCha20 பகிரப்பட்ட விசையிலிருந்து பெறுகிறது:
ஏன் 32 பைட்டுகளுக்கு துண்டிக்கப்படுகிறது?
Wi-Fi Aware PMK சரியாக 32 பைட்டுகள் (256 பிட்) ஆக இருக்க வேண்டும். பெயரிங்கிலிருந்து
ChaCha20 பகிரப்பட்ட விசை இயல்பான வழக்கில் 32 பைட்டுகள், எனவே raw.size == 32 கிளை
பொதுவான பாதை. துண்டிப்பு/திணிப்பு fallback விசை குறைவாக சேமிக்கப்பட்ட (கோட்பாட்டு)
வழக்கைக் கையாளுகிறது — 32 பைட்டுகளுக்கு பூஜ்யங்களுடன் திணிப்பது ஒரு தற்காப்பு
நடவடிக்கை, சரியாகப் பெயர் செய்த பியர்களுடன் நடைமுறையில் நிகழ்வதில்லை.
கையொப்பமிடப்பட்ட உறை LAN-உடன் ஒரே மாதிரி
createCryptoHttpClient LanTransport-ஆல் பயன்படுத்தப்படும் அதே factory என்பதால், Aware-இல்
L7 மறைகுறியாக்கம் LAN-உடன் byte-for-byte ஒரே மாதிரி. சேவையக-பக்க PeerGraphQLService
எந்தப் போக்குவரத்து கோரிக்கையை வழங்கியது என்பதை அறியாது (அல்லது கவலைப்படாது) — அது
வெறுமனே ஒரு கையொப்பமிடப்பட்ட, மறைகுறியாக்கப்பட்ட GraphQL சுமையைப் பார்த்து, பியரின்
பகிரப்பட்ட விசையுடன் மறைநீக்குகிறது. இதுதான் அரட்டைக் கட்டமைப்பு-இல்
ஆவணப்படுத்தப்பட்ட "ஒரு குறியீட்டுத்தளம், பல போக்குவரத்துகள்" கொள்கை.
செய்தி அனுப்பல் பாதை (முழுமையான) {#message-send-path-end-to-end}
எல்லாவற்றையும் ஒன்றிணைத்தால் — ஒரு அரட்டைச் செய்தி Wi-Fi Aware வழியாக அனுப்பப்படும்போது என்ன நிகழ்கிறது:
குறிப்பிடத்தக்க வடிவமைப்புத் தேர்வுகள்
- இணைப்பு மறுபயன்பாடு.
BleTransport-போல அல்லாமல், அது ஒவ்வொரு கோரிக்கைக்கும் பிறகும் GATT இணைப்பை இடிக்கிறது,WifiAwareTransport60 வி ஒருங்கிணைந்த சாளரத்திற்குள் பயனர் செய்யும் பல கோரிக்கைகளுக்கும் Aware தரவுப் பாதையை மறுபயன்பாடு செய்கிறது. முதல் கோரிக்கை ~400 ms handshake-ஐச் செலுத்துகிறது; அடுத்தடுத்த கோரிக்கைகள் ~10 ms ரவுண்ட் ட்ரிப்கள். - LAN-ன் அதே மறைகுறியாக்கம். ChaCha20 இடைமறிப்பான் மற்றும் கையொப்பமிடப்பட்ட உறை
LAN-உடன் byte-ஒரே மாதிரி. பியரின்
PeerGraphQLServiceஎந்தப் போக்குவரத்து கோரிக்கையை வழங்கியது என்பதை அறியாது. - இணைப்பு தோல்வியில் preemption இல்லை.
buildLinkதோல்வியடைந்தால், போக்குவரத்துTransportUnavailable-ஐ வீசி ரூட்டர் BLE-க்கு விழுகிறது.send-இல் மறுமுயற்சி இல்லை —AwarePeerLink.buildஏற்கனவே அதன் சொந்த உள் மறுமுயற்சி வளையத்தைச் செய்கிறது (கிளையன்ட்டில்MAX_BUILD_ATTEMPTS = 1, prewarmer இரு தரப்பையும் primed செய்திருந்தால் அதிகம்).
கோப்பு பதிவிறக்கப் பாதை (முழுமையான) {#file-download-path-end-to-end}
Aware வழியாக கோப்பு பதிவிறக்கங்கள் அரட்டைச் செய்திகளைப் போல அதே தரவுப் பாதையை மறுபயன்பாடு செய்கின்றன, ஆனால் பெரிய கோப்புகளை ஸ்ட்ரீம் செய்வதற்கு உள்ளமைக்கப்பட்ட தனி OkHttp கிளையன்ட்-ஐப் பயன்படுத்துகின்றன:
பதிவிறக்கங்களுக்கு ஏன் தனி கிளையன்ட்?
அரட்டை கிளையன்ட் (AwareHttpClientFactory.build) 30 வி
requestTimeoutMillis-ஐக் கொண்டுள்ளது — GraphQL mutations-க்கு பொருத்தமானது ஆனால்
100 MB கோப்பு பதிவிறக்கத்திற்கு பேரழிவு. பதிவிறக்க கிளையன்ட்
(buildFileDownload) பின்வருவனவற்றை அமைக்கிறது:
connectTimeoutMillis = 10_000(அரட்டையின் 5 வி-விட அதிகம், புதிய தரவுப் பாதையில் மெதுவான முதல்-பாக்கெட்டை அதிக சகிப்புத்தன்மை கொண்டது)- ஒரு வாசிப்புக்கு
readTimeout = 120 வி(10 வி இயல்புநிலைக்கு பதிலாக) requestTimeoutMillis = 120_000(2 நிமிடங்கள் — பெரும்பாலான கோப்புகளுக்குப் போதுமானது)retryOnConnectionFailure(true)— கைவிடப்பட்ட நடு-பதிவிறக்க வாசிப்பு மறுமுயற்சி செய்யப்படுகிறது, முழு பரிமாற்றத்தையும் தோல்வியடையச் செய்வதற்கு பதிலாக
இது மேலும் ChaCha20 இடைமறிப்பானைத் தவிர்க்கிறது. /fs endpoint raw கோப்பு பைட்டுகளை
வழங்குகிறது (கையொப்பமிடப்பட்ட GraphQL உறை அல்ல), மற்றும் L2 PMK (இருக்கும்போது)
ஏற்கனவே ரேடியோ இணைப்பை மறைகுறியாக்குகிறது. ஒரு 50 MB வீடியோவை ChaCha20-உடன்
மென்பொருளில் இரட்டை-மறைகுறியாக்கம் செய்வது CPU-ஐ வீணாக்கி பரிமாற்றத்தை மெதுவாக்கும்.
ஸ்ட்ரீமிங், buffering அல்ல
BLE பாதையைப் போல, Aware பதிவிறக்கங்கள் கோப்பை ஒரு ByteReadChannel வழியாக
ஸ்ட்ரீம் செய்கின்றன — கோப்பு பைட்டுகள் வரும்போது தற்காலிகக் கோப்பில் எழுதப்படுகிறது,
நினைவகத்தில் buffer செய்யப்படவில்லை. PeerFileDownloader 8 KB துண்டுகளைப் படித்து
ஒவ்வொரு விநாடியும் முன்னேற்ற நிகழ்வுகளை வெளியிடுகிறது. அதே DownloadedResponse /
PeerFileDownloader / DownloadQueue பைப்லைன் எல்லா போக்குவரத்துகளிலும் மறுபயன்பாடு
செய்யப்படுகிறது — போக்குவரத்து-குறிப்பிட்டது channel மூலம் மட்டுமே.
Prewarming: BLE-தூண்டப்பட்ட Aware தொடக்கம் {#prewarming-ble-triggered-aware-startup}
Aware பாதையில் மிகப் பெரிய பயனர்-காணக்கூடிய தாமதம் முதல் handshake — இரு தரப்பும் இன்னும் Aware-ஐத் தொடங்காவிட்டால், பயனரின் முதல் செய்தி பின்வருவனவற்றிற்காக காத்திருக்க வேண்டும்:
- உள்ளக Aware அமர்வு attach (~1 வி)
- உள்ளக publish + subscribe தொடக்கம் (~1 வி)
- தொலைநிலை பியரின் Aware தொடக்கம் (~2 வி BLE வழியாக)
- பரஸ்பர கண்டுபிடிப்பு (~1 வி)
- NDP handshake (~400 ms)
இது முதல் பைட் அனுப்பப்படுவதற்கு முன்பு ~5 விநாடிகள். இந்தத் தாமதத்தை மறைக்க,
PeerTransportPrewarmer ChatPage நுழைவில் இயங்கி, தொலைநிலை பியரின் Aware தொடக்கத்தை
BLE வழியாகத் தூண்டுகிறது:
BLE-ன் இரட்டை பங்கு
BLE இங்கே இரண்டு நோக்கங்களை சேவையாற்றுகிறது:
- பியரின் தற்போதைய Aware நிலையைப் படி (மலிவானது, GATT connect இல்லை — ஸ்கேன்
பதிலின்
serviceDatabyte0 Aware கொடிகளைக் கொண்டு செல்கிறது). - பியர் Aware-ஐத் தொடங்கத் தூண்டு அது ஆதரித்தாலும் தற்போது அதை இயக்கவில்லை என்றால்.
இது வழக்கமான
BleTransport.sendபாதையைப் பயன்படுத்துகிறது — ஒருstartAwareGraphQL mutation பகிரப்பட்ட ChaCha20 விசையுடன் மறைகுறியாக்கப்பட்டு, GATT RPC வழியாகப் பியரின்/peer_graphqlendpoint-க்கு வழங்கப்படுகிறது.
இது போக்குவரத்துகள் வெறுமனே fallback செய்வதற்குப் பதிலாக ஒத்துழைக்கும் சில இடங்களில் ஒன்று: BLE பயனர் கவனிக்கும் முன்பே அமர்வை வேகமான Aware போக்குவரத்திற்கு pre-emptively upgrade செய்யப் பயன்படுகிறது.
ஏன் நம்பிக்கையுடன் setAwareRunning(true)?
startAware mutation தொலைநிலை பியரின் resolver WifiAwareTransport.start()-ஐ அழைக்கும்
வேளை வெற்றியைத் திருப்பி அனுப்புகிறது — ஆனால் Aware அமர்வு உண்மையில் attach
செய்யப்படவில்லை (onAttached asynchronous ஆக இயங்குகிறது). PlainApp பியரை
நம்பிக்கையுடன் awareRunning = true எனக் குறிக்கிறது, ஏனெனில்:
- அது உண்மையில் தொடங்கினால், அடுத்த
sendAware-ஐப் பயன்படுத்தும் (விரைவானது). - அது இல்லையென்றால் (உ.ம். பியரின் Wi-Fi ஆஃப்), அடுத்த
send-ன்buildLinkTransportUnavailableஉடன் தோல்வியடைந்து இயற்கையாக BLE-க்கு fallback செய்யும். - ஒரு false positive-ன் செலவு ஒரு ~5 வி நேரமுடிவு, நிரந்தர block அல்ல —
PeerCircuitBreakerதோல்வியைப் பதிவு செய்கிறது ஆனால் BLE காலைத் திறப்பதில்லை (BLE அதன் சொந்த தோல்விகளில் மட்டுமே திறக்கிறது).
ஏன் 30 வி-க்கு throttle?
PeerTransportPrewarmer.prewarm(peerId) ஒரு பியருக்கு ஒரு நேரமுத்திரையைப் பதிவு செய்து
30 வி-க்குள் மறு-இயக்கம் செய்ய மறுக்கிறது. இது ஏனெனில் பயனர் அரட்டை பட்டியல் மற்றும்
அரட்டைப் பக்கத்திற்கு இடையில் அடிக்கடி வந்து செல்கிறார் — throttle இல்லாமல், ஒவ்வொரு
navigation-உம் ஒரு BLE ஸ்கேன் + startAware mutation-ஐத் தூண்டும், பேட்டரியை வடிகட்டி
BLE ரேடியோவை spam செய்யும். 30 வி சாளரம் வெறுமனே ஆன்லைனில் வந்த ஒரு பியரைப்
பிடிக்கப் போதுமான அளவு குறுகியது (உ.ம். பயனர் தொலைநிலை சாதனத்தில் செயலியைத் திறந்தார்)
ஆனால் போலி மறு-இயக்கங்களைத் தவிர்க்கப் போதுமான அளவு நீண்டது.
தோல்வி முறைகள் & விரைவு-தவிர் கொடி {#failure-modes--the-fast-skip-flag}
Aware மற்ற எந்தப் போக்குவரத்தை விடவும் அதிக தோல்வி முறைகளைக் கொண்டுள்ளது.
isAwareRunning விரைவு-தவிர் கொடி முழு தொகுதியிலும் மிக முக்கியமான optimization —
இது இல்லாவிட்டால், ஒவ்வொரு send-உம் BLE-க்கு fallback செய்வதற்கு முன்பு buildLink
நேரமுடிவில் 10 வி-ஐ வீணாக்கும்.
isAwareRunning கொடி linchpin
இந்த ஒற்றை boolean இல்லாமல், ஒவ்வொரு Aware send-உம்:
- எப்போதும்
buildLink-ஐ முயற்சிக்கும் → Aware இயங்காத ஒரு பியருக்கு ஒவ்வொரு send-இலும் 10 வி நேரமுடிவு. - எப்போதும் Aware-ஐத் தவிர்க்கும் → இரு தரப்பும் அதை இயக்கும்போதும் ஒருபோதும் பயன்படுத்தாது.
கொடி இரண்டு மூலங்களிலிருந்து, அதிகாரத்தின் வரிசையில் புதுப்பிக்கப்படுகிறது:
- BLE ஸ்கேன் பதில் (மலிவானது, GATT connect இல்லை) —
PeerTransportPrewarmer.refreshAwareFlagFromScan-ஆல் அமைக்கப்படுகிறது. பியர் அதன் Aware நிலையை 9-பைட்serviceDataசுமையில் (byte0 bitfield) விளம்பரப்படுத்துகிறது. - GATT DISCOVER பதில் (அதிகாரப்பூர்வமானது) — முழு கண்டுபிடிப்பு நிகழும்போது
PairingTransport.scanAndDiscover-ஆல் அமைக்கப்படுகிறது. இது ஸ்கேன் குறிப்பை மேலெழுதுகிறது.
False ஆக இருக்கும்போது, WifiAwareTransport.send மற்றும் downloadFile உடனடியாக
TransportUnavailable-ஐ வீசுகின்றன — ஸ்கேன் இல்லை, handshake இல்லை, நேரமுடிவு இல்லை.
ரூட்டர் microseconds-இல் BLE-க்கு விழுகிறது.
முக்கிய மாறிலிகள் குறிப்பு {#key-constants-reference}
| மாறிலி | மதிப்பு | எங்கே | நோக்கம் |
|---|---|---|---|
AwareSession.SERVICE_NAME | "plain-peer" | கண்டுபிடிப்பு | ஒவ்வொரு PlainApp சாதனத்தாலும் வெளியிடப்பட்டு subscribe செய்யப்பட்ட சேவைப் பெயர் |
AwareSession.PEER_HANDLE_MAX_AGE_MS | 30 000 | PeerHandle cache | பழைய handles-ஐ நீக்கு (பியரின் publish அமர்வு மறுதொடக்கம் செய்யப்பட்டிருக்கலாம்) |
AwareSession.READY_TIMEOUT_MS | 15 000 | Handshake | publisher-ன் ready ரசீதுக்காக subscriber காத்திருப்பு |
AwareSession.MSG_HELLO | 0 | Handshake | Subscriber → Publisher செய்தி ID |
AwareSession.MSG_READY | 1 | Handshake | Publisher → Subscriber செய்தி ID |
AwarePeerLink.MAX_BUILD_ATTEMPTS | 1 | Handshake (கிளையன்ட் மட்டும்) | ஒற்றை முயற்சி — 3 ஆக இருந்தது, இப்போது 1 ஏனெனில் prewarmer இரு தரப்பையும் primes |
AwarePeerLink.ATTEMPT_TIMEOUT_MS | 5 000 | Handshake | ஒரு-முயற்சி நேரமுடிவு — 10 வி ஆக இருந்தது, fallback-ஐ வேகப்படுத்த பாதி செய்யப்பட்டது |
AwarePeerLink.RETRY_DELAY_MS | 500 | Handshake | மறுமுயற்சி முயற்சிகளுக்கு இடையிலான தாமதம் (கிளையன்ட் மட்டும்) |
AwarePeerLink.REQUEST_TIMEOUT_MS | 30 000 | NDP | connectivityManager.requestNetwork நேரமுடிவு |
AwareLinkPool.IDLE_TIMEOUT_MS | 60 000 | Pool sweep | 60 வி செயல்பாடின்மைக்குப் பிறகு ஒருங்கிணைந்த இணைப்புகளை மூடு |
AwareLinkPool.IDLE_SWEEP_INTERVAL_MS | 10 000 | Pool sweep | Sweep இடைவெளி |
AwareHttpClientFactory.AWARE_HOST | "plain-aware-peer" | DNS | தனிப்பயன் Dns-ஆல் peer IPv6-க்கு தீர்மானிக்கப்பட்ட Sentinel hostname |
build அரட்டை கிளையன்ட் | connectTimeout 5 வி, requestTimeout 30 வி, ChaCha20 இடைமறிப்பான் | ||
buildFileDownload | connectTimeout 10 வி, readTimeout 120 வி, requestTimeout 120 வி, மறைகுறியாக்கம் இல்லை | ||
PeerTransportPrewarmer.PREWARM_TTL_MS | 30 000 | Prewarm | ஒரு பியருக்கு throttle |
PeerTransportPrewarmer.BLE_SCAN_TIMEOUT_MS | 15 000 | Prewarm | refreshAwareFlagFromScan-க்கான BLE ஸ்கேன் நேரமுடிவு |
PeerCircuitBreaker.WINDOW_MS | 30 000 | Circuit breaker | வாசலுக்குப் பிறகு திறக்கும் காலம் |
PeerCircuitBreaker.MAX_FAILURES | 2 | Circuit breaker | திறக்க வாசலுக்குள் தோல்விகள் |
TempData.httpsPort | 8443 (இயல்புநிலை) | Server | WifiAwareNetworkSpecifier.setPort வழியாக விளம்பரப்படுத்தப்பட்ட Publisher-ன் port |
BleServiceData.AWARE_SUPPORTED | 0x01 | BLE ஸ்கேன் பதில் | பியர் Wi-Fi Aware-ஐ ஆதரிக்கிறார் என்பதைக் குறிக்கும் bit |
BleServiceData.AWARE_RUNNING | 0x02 | BLE ஸ்கேன் பதில் | பியரின் Aware சேவை தற்போது இயங்குகிறது என்பதைக் குறிக்கும் bit |
வடிவமைப்பு பரிமாற்றங்கள் சுருக்கம் {#design-trade-offs-recap}
மேலும் படிப்பதற்கு
- அரட்டைக் கட்டமைப்பு —
WifiAwareTransportஎப்படிLAN → Aware → BLEfallback சங்கிலி மற்றும் பரந்த அரட்டை அனுப்பு/பெறு பைப்லைனுக்குள் பொருந்துகிறது. - BLE போக்குவரத்து — Aware கிடைக்காதபோது ஏற்றுக்கொள்ளும் கடைசி-முயற்சி போக்குவரத்து; மேலும் prewarmer தொலைநிலை பியரில் Aware தொடக்கத்தைத் தூண்டப் பயன்படுத்தும் சேனல்.
- பெயரிங் பாய்வு — Aware PMK-ஆக மீண்டும் பயன்படுத்தப்படும்
பகிரப்பட்ட ChaCha20 விசை எப்படி நிறுவப்படுகிறது, மற்றும் BLE ஸ்கேன் பதில் கொடிகள்
(
AWARE_SUPPORTED/AWARE_RUNNING) எப்படி populate செய்யப்படுகின்றன.