Android WIFI認證的流程
當用戶開啟wifi,掃描完成之後,當用戶點選AP列表中一項並輸入正確的密碼後,就可以開始AP的連線過程了.點選連線到最終連線成功,這個過程中具體流程是如何實現的,這篇文章,將介紹一下這個流程;其使用者介面顯示過程如下:
我們現有的AP有兩種方式:有密碼保護的連線和無密碼保護的連線。其實這兩種方式的主要區別在於有密碼保護的AP連線過程需要在UI上彈出一個輸入密碼的介面給使用者。輸入密碼之後點選連線就和無密碼保護的連線過程的總體流程是一樣的,只不過有密碼保護的呼叫的方法多一點。
2.1 程式碼流程
在LINUX/android/packages/apps/Settings/res/values/strings.xml檔案中對於connect有如下的程式碼:
<string name="wifi_menu_connect">Connect to network</string> |
在LINUX/android/packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java檔案中對於Connect選項有如下的程式碼:
public class WifiSettings extends RestrictedSettingsFragment implements View.OnClickListener, DialogInterface.OnClickListener { private static final int MENU_ID_CONNECT = Menu.FIRST + 6; public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) { menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect); } public boolean onContextItemSelected(MenuItem item) { case MENU_ID_CONNECT if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) { mWifiManager.connect(mSelectedAccessPoint.networkId, mConnectListener); } else if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE) { mSelectedAccessPoint.generateOpenNetworkConfig(); mWifiManager.connect(mSelectedAccessPoint.getConfig(), mConnectListener); } else { showDialog(mSelectedAccessPoint, true); } return true; } } |
INVALID_NETWORK_ID值的意思是當前連線的AP是一個新的AP(之前沒有連線過);從上面的程式碼可以看出當點選連線之後程式碼會首先對AP是否是新的AP連線和是否有密碼保護進行判斷,這兩種情況都會直接呼叫connect函式進行連線。如果有密碼的AP連線則顯示密碼視窗進行連線,關於這部分我們將在第二節進行分析;接下來我們分析無密碼或者新AP的AP連線過程;呼叫LINUX/android/frameworks/base/wifi/
java/android/net/wifi/WifiManager.java中的connect函式,如下:
public void connect(WifiConfiguration config, ActionListener listener) { writeBackTrace(); validateChannel(); sAsyncChannel.sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID, putListener(listener), config); } |
其中第一個引數WifiConfiguration是當前需要連線的AP的配置資訊,包括SSID、BSSID、密碼以及加密方式等資訊;ActionListern作為callback來通知客戶程式connect方法是否呼叫成功,這裡的呼叫成功只是指引數是否正確,並不表示AP是否連線成功。在LINUX/android/frameworks/base/wifi/java/android/net/wifi/
WifiService.java中去看看如果處理CONNECT_NETWORK這個訊息:
case WifiManager.CONNECT_NETWORK: { if (config != null && config.isValid()) { if (config.proxySettings != ProxySettings.PAC) { mWifiStateMachine.sendMessage(Message.obtain(msg)); } } |
WifiService將這個訊息傳遞給WifiStateMachine處理,這時候LINUX/android/frameworks/base/wifi/java/
android/net/wifi/WifiStateMachine.java的ConnectModeState將處理CONNECT_NETWORK這個訊息,程式碼如下:
case WifiManager.CONNECT_NETWORK: if (config != null) { NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); } if (mWifiConfigStore.selectNetwork(netId) && mWifiNative.reconnect()) { mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); transitionTo(mDisconnectingState); } |
這裡主要呼叫了下面幾個函式來進行AP的連線:WifiConfigStore.saveNetwok(config)將AP的配置資訊寫入到wpa_supplicant.conf中;WifiConfigStore.selectNetwork(netId)用於enable即將要連線的AP,而disable掉其它的AP;WifiNative.reconnect()發起重新連線的請求給wpa_supplicant。同時傳送了兩個訊息,一個是給wpa_suppicant傳送的訊息;SupplicantStateTracker用於監視wpa_supplicant的狀態;replyToMessage用於給WifiSettings傳送訊息,說明connect函式已經呼叫成功;接著transition到DisconnectingState中,來看看DisconnectingState,這個狀態code比較少:
class DisconnectingState extends State { @Override public boolean processMessage(Message message) { case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: deferMessage(message); handleNetworkDisconnect(); transitionTo(mDisconnectedState); break; default: return NOT_HANDLED; } } |
當執行完WifiNative.reconnect(),wpa_supplicant會不斷的往WifiMonitor傳送包括CTRL-EVENT-STATE-CHANGE、ASSOCIATING、ASSOCIATED、FOUR_WAY_HANDSHARK、GROUP_HANDSHARK等event,WifiMonitor會不斷的去parse這些event並向WifiStatemachine傳送訊息,其中一個比較重要的訊息就是當wpa_supplicant的狀態改變是會發送WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT,上面的DisconnectiongState 收到這個訊息後,會transition到DisconnectedState。NOT_HANDLED的意思是沒有處理這種情況下將會交給起父狀態去處理;當Wifi和AP之間已經連線成功後,WifiMonitor就會收到wpa_supplicant傳送上來的CTRL-EVENT-CONNECTED這個event,WifiMonitor收到這個訊息後,會向WifiStateMachine傳送NETWORK_CONNECTION_EVENT表示已經和AP之間成功的連線,WifiStateMachine的ConnectModeState會來處理這個訊息,程式碼如下:
case WifiMonitor.NETWORK_CONNECTION_EVENT: transitionTo(mObtainingIpState); break; |
上面的程式碼可以看出連線成功之後將會轉到IP申請階段;進入到ObtainingIpState狀態,到ObtainingIpState的enter函式:
class ObtainingIpState extends State { @Override public void enter() { if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { startDhcp(); } else { 省略程式碼 } } } |
ObtainingIpState就是獲取IP的狀態,這裡分為兩種獲取IP的方式,一種是使用者靜態配置的,另一種是通過DHCP動態分配。這裡只看動態分配的,進到到startDhcp去分析:
void startDhcp() { mDhcpStateMachine.registerForPreDhcpNotification(); mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); } |
首先去建立DhcpStateMachine的例項,然後向它傳送一個CMD_START_DHCP的命令,LINUX/android/
frameworks/base/core/java/android/net/DhcpStateMachine.java初始化完畢後,對CMD_START_DHCP進行處理,程式碼如下:
case CMD_START_DHCP: if (mRegisteredForPreDhcpNotification) { mController.sendMessage(CMD_PRE_DHCP_ACTION); transitionTo(mWaitBeforeStartState); } |
收到CMD_START_DHCP訊息就會馬上向WifiStateMachine傳送CMD_PRE_DHCP_ACTION表示DhcpStateMachine馬上就要開始傳送discovery或者renew的封包了,來看WifiStateMachine收到這個訊息的處理:
class L2ConnectedState extends State { public boolean processMessage(Message message) { switch (message.what) { case DhcpStateMachine.CMD_PRE_DHCP_ACTION: handlePreDhcpSetup(); break; } } } void handlePreDhcpSetup() { mDhcpActive = true; if (!mBluetoothConnectionActive) { mWifiNative.setBluetoothCoexistenceMode( mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); } msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE; mWifiP2pChannel.sendMessage(msg); } |
在處理CMD_PRE_DHCP_ACTION中呼叫handlePreDhcpSetup函式主要是設定BT共存模式、關閉P2P
Powersave等功能,並且WifiStateMachine會向LINUX/android/frameworks/base/core/java/android/net/
DhcpStateMachine.java傳送CMD_PRE_DHCP_ACTION_COMPLETE,用於指示前期準備工作已經做好了,當DhcpStateMachine收到CMD_PRE_DHCP_ACTION_COMPLETE命令後就可以開始dhcp的discovery/reponse了,用於兩端來獲取IP,程式碼如下:
class WaitBeforeStartState extends State { case CMD_PRE_DHCP_ACTION_COMPLETE: if (runDhcp(DhcpAction.START)) { transitionTo(mRunningState); } else { transitionTo(mStoppedState); } break; } private boolean runDhcp(DhcpAction dhcpAction) { boolean success = false; DhcpResults dhcpResults = new DhcpResults(); dhcpResults.autoip = getAutoIpSettings(); if (dhcpAction == DhcpAction.START) { NetworkUtils.stopDhcp(mInterfaceName); success = NetworkUtils.runDhcp(mInterfaceName, dhcpResults); } mDhcpResults = dhcpResults; mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpResults) .sendToTarget(); return success; } |
如上的程式碼會對CMD_PRE_DHCP_ACTION_COMPLETE訊息進行處理,會呼叫runDhcp函式進行獲取IP的操作。當IP成功獲取後,DhcpStateMachine會給WifiStateMachine傳送CMD_POST_DHCP_ACTION訊息,WifiStateMachine收到訊息後做如下的處理:
class L2ConnectedState extends State { case DhcpStateMachine.CMD_POST_DHCP_ACTION: handlePostDhcpSetup(); if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { handleSuccessfulIpConfiguration((DhcpResults) message.obj); transitionTo(mVerifyingLinkState); } } |
其中arg1表示是成功還是失敗,如果成功,呼叫WifiStateMachine自身的handleSuccessfulIpConfiguration來處理,並transition 到VerifyingLinkState中;如果失敗則會transition到DisconectingState中。這裡只看成功獲取IP的情況,進入到VerifyingLinkState中:
class VerifyingLinkState extends State { public boolean processMessage(Message message) { switch (message.what) { case WifiWatchdogStateMachine.POOR_LINK_DETECTED: //stay here break; case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: transitionTo(mCaptivePortalCheckState); break; default: return NOT_HANDLED; } return HANDLED; } } |
在VerifyingLinkState主要是來驗證當前連線狀況的,主要方式是通過統計訊號強度以及丟包率,這些工作是交給WifiWatchdogStateMachine來做的,當WifiAP的訊號強度增強或者變弱,會發送兩種訊息給WifiStateMachine,一種是WifiWatchdogStateMachine.GOOD_LINK_DETECTED,另一種是WifiWatchdogStateMachine.POOR_LINK_DETECTED。當收到GOOD_LINK_DETECTED訊息後,就會跳轉到CaptivePortalCheckState中;當收到的是POOR_LINK_DETECTED,則維持原來的狀態不變。我們跳轉到CaptivePortalCheckState去分析:
class CaptivePortalCheckState extends State { public boolean processMessage(Message message) { switch (message.what) { case CMD_CAPTIVE_CHECK_COMPLETE: mNwService.enableIpv6(mInterfaceName); setNetworkDetailedState(DetailedState.CONNECTED); mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); sendNetworkStateChangeBroadcast(mLastBssid); transitionTo(mConnectedState); break; } return HANDLED; } } |
首先會發送CAPTIVE_PORTAL_CHECK的broadcast,這個會被WifiStateTracker接收並處理,然後呼叫ConnectivityService的介面去處理captive portal相關的內容.當ConnectivityService完成captive portal check後,就會給WifiStateMachine傳送CMD_CAPTIVE_CHECK_COMPLETE訊息,就會跳轉到ConnectedState表示連線過程的結束了。
2.2 Log流程
以下的Log中資訊中我增加了很多自己的Log標誌,主要目的是要清晰地根據Log看出程式碼的流程;以下是Log的內容,有些粗糙還望海涵;
writeBackTrace函式中判斷isWriteBackTraceEnabled為真之後就會列印這條Log,並且建立Throwable的物件以下為建立時所列印的Log資訊; 第一部分:進入WifiManager中的connect函式首先呼叫writeBackTrace函式,會列印第一部分;
第二部分:WifiService收到CONNECT_NETWORK訊息訊息之後,首先列印config的內容,這部分主要是config的內容;接著會將CONNECT_NETWORK訊息傳送給WifiStateMachine處理;
接下來看一下 WifiStateMachine對CONNECT_NETWORK訊息的處理Log資訊(具體的解釋請砍Log後面的註釋):
在完成上述的操作之後,在addOrUpdateNetworkNative函式中呼叫WifiNative檔案中setNetworkVariable函式去設定網路的一些引數。當addOrUpdateNetworkNative函式完成SET之後會呼叫readNetworkVariables函式,在readNetworkVariables函式中會呼叫WifiNative檔案中的getNetworkVariable函式去獲取網路引數的操作,由於獲取引數比較得多我們此處的Log資訊只列出一部分:
完成獲取之後,在saveNetwork函式其次會呼叫WifiNative檔案中的enableNetwork函式,就會發送ENABLE_NETWORK命令給wpa_supplicant;wpa_supplicant在處理ENABLE_NETWORK命令的時候回去傳送連線的請求;
傳送了連線請求之後,接著在saveNetwork函式會呼叫WifiNative檔案中的saveConfig函式,就會下發SAVE_CONFIG給wpa_supplicant。wpa_supplicant會返回要連線的AP的資訊;
WifiStateMachine收到CONNECT_NETWORK訊息之後會其次呼叫WifiConfigStore檔案中的selectNetwork函式;selectNetwork函式會首先呼叫(1)addOrUpdateNetworkNative函式,接下來又是上面的那一套SET和GET的呼叫;因與前面的呼叫一樣(個人覺得此處是重複,但不知道設計者有什麼深層的含義)所以此處只列出一部分Log資訊。完成 SET和GET的呼叫之後,selectNetwork函式會其次呼叫(2)WifiNative檔案中的saveConfig函式向wpa_supplicant傳送命令SAVE_CONFIG;此處與前面的操作又重複;
selectNetwork函式接著呼叫enableNetworkWithoutBroadcast函式,enableNetworkWithoutBroadcast呼叫WifiNative檔案中的enableNetwork函式向wpa_supplicant傳送命令SELECT_NETWORK;
WifiStateMachine收到CONNECT_NETWORK訊息之後會最後呼叫WifiNative檔案中的reconnect函式;reconnect函式會向wpa_supplicant傳送RECONNECT命令;之後就是對connect的處理;
接下來就是連線操作,以及Ip的申請此處我只說到成功連線的部分;關於其他的我不再在此說明;到CTRL-EVENT-CONNECTED這條Log資訊說明Ap已經連結,之後就是Ip的申請等等操作;
相關推薦
Android WIFI認證的流程
當用戶開啟wifi,掃描完成之後,當用戶點選AP列表中一項並輸入正確的密碼後,就可以開始AP的連線過程了.點選連線到最終連線成功,這個過程中具體流程是如何實現的,這篇文章,將介紹一下這個流程;其使用者介面顯示過程如下: 我們現有的AP有兩種方式:有密碼保護的
Android wifi 掃描流程 分析
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) { int res; if (wpa_s->p2p_mgmt) { wpa_dbg(wpa_s, MSG_DEBU
Android wifi開啟流程(Android O)
根據自己的理解整理了Android O的wifi啟動流程,為便於理解,繪製了Android O wifi架構圖。有理解不到之處和錯誤之處,請各位指出,一起學習。 一. Android O wifi 架構: 由於Android O的Treble化,Android O
Android Wifi框架流程分析
//在 SystemServer 啟動的時候,啟動WifiService呼叫關係如下: public static void main(String[] args) { new SystemServer().run(); } pr
Android之wifi工作流程
Android Wifi的工作流程 一、WIFI工作相關部分 Wifi 網絡卡狀態 1. WIFI_STATE_DISABLED:WIFI網絡卡不可用 2. WIFI_STATE_DISAB
(九十三) Android O 連線WiFi AP流程梳理續-儲存網路
前言: 之前在(五十五)Android O 連線WiFi AP流程梳理 梳理連線流程梳理到SupplicantStaNetworkHal 然後沒梳理的下去,現在繼續梳理下。 之前梳理的時序圖 1.流程梳理-儲存網路 現在重新梳理了下流程發現漏了些細節,完善一
(九十四) Android O 連線WiFi AP流程梳理續——連線網路
前言: 之前在(五十五)Android O 連線WiFi AP流程梳理 梳理連線流程梳理到SupplicantStaNetworkHal 然後沒梳理的下去,現在繼續梳理下。 相關梳理: 1)(九十三) Android O 連線WiFi AP流程梳理續——儲存網路 2)&nb
Android WiFi使用記錄
enc nts sum cap anr eat index etc 清空 最近在做Android的WiFi部分的開發,連接的工具類參照了這個文章的工具類。 http://www.cnblogs.com/zhuqiang/p/3566686.html 開發中碰上的
Android系統啟動流程(一)解析init進程啟動過程
option 寫入 android change failed miss 通知 target sna 前言 作為“Android框架層”這個大系列中的第一個系列,我們首先要了解的是Android系統啟動流程,在這個流程中會涉及到很多重要的知識點,這個系列我們就來一一講解它們
wifi認證Portal開發系列(三):portal協議
tro spa size http log ron 認證 gin auto 中國移動WLAN業務PORTAL協議規範介紹 wifi認證Portal開發系列(三):portal協議
android -------- WIFI 詳解
mov 取ip地址 fico alt b- else if 無線網 pan PC 今天簡單的來聊一下安卓開發中的Wifi,一些常用的基礎,主要分為兩部分: 1:WiFi的信息 2:WiFi的搜索和連接 現在app大多都需要從網絡上獲得數據。所以訪問網絡是在
Android系統啟動流程
包名 more dev ted androi cap 執行 ons 開始 當系統引導程序啟動Linux內核,內核會記載各種數據結構,和驅動程序,加載完畢之後,Android系統開始啟動並加載第一個用戶級別的進程:init(system/core/init/Init.c)
微信小程序的認證流程,極限工坊一步一步教會你
nag 進行 text 根據 服務號 登陸 dad 訂閱號 手機號碼 微信小程序作為一種輕巧靈活的手機應用,改變著手機互聯網形態的同時,也在改變著我們的生活方式。 下面淘小咖具體教大家如何輕松快捷註冊小程序,看圖教程一步一步來! 1、小程序賬號註冊 百度搜索或者直接在公眾平
關於ios 11.X後微信wifi認證,無法打開微信,無法重定向到weixin:開頭網址等問題的處理
width 問題 aos 開頭 優化 重定向 bubuko gin indexof 環境: 認證路由ROS ,認證後臺python django ios11系統 更新以來先後出現微信wifi認證,無法打開微信,無法重定向到weixin:開頭網址等相關問題。 經
Android wifi狀態三種廣播,可以監測wifi狀態變化
轉至:http://www.blogjava.net/liuyanbo/archive/2012/09/17/387882.html public class NetworkConnectChangedReceiver extends BroadcastR
關於ios 11.X後微信wifi認證,無法開啟微信,無法重定向到weixin:開頭網址等問題的處理
環境: 認證路由ROS ,認證後臺python django ios11系統 更新以來先後出現微信wifi認證,無法開啟微信,無法重定向到weixin:開頭網址等相關問題。 經過問題的收集,查詢到網路上此類問題普遍存在 收集到的有如下網址,市面上大多數廠商在使用
Android WiFi 系統架構
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Django rest framework 的認證流程(原始碼分析一)
一、基本流程舉例: urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^users/', views.HostView.as_view()), ] urls
android wifi p2p / wifi direct
版權宣告:本文為博主原創文章,未經博主允許不得轉載。https://blog.csdn.net/h784707460/article/details/81502574 一. wifi P2P協議相關 Wi-Fi Alliance(Wi-Fi聯盟)推出的一項重要技術規範Wi-
Android WiFi--系統架構
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!