簡單分析下wifi相關類,首先了解幾個主要概念html
AsyncChanneljava
簡單理解:android
AsyncChannel,就是藉助Messenger 機制,讓兩個不一樣的handler之間進行通訊。shell
AsyncChannel類有兩個Messenger對象:mSrcMessenger,mDstMessenger。安全
mSrcMessenger,通常用於封裝源端handler對象服務器
mDstMessenger,通常用於封裝目的端handler對象網絡
然後,調用AsyncChannel的sendMessage方法時,執行兩個操做:socket
1. msg.replyTo = mSrcMessenger; //重設消息的replyTo值函數
2. mDstMessenger.send(msg); //該方法就會將消息發送給目的端的handler去處理測試
因爲重設了消息的replyTo值,以後在目的端發出的消息,將返回給源端handler處理。
參考:Android源碼閱讀筆記:AsyncChannel與層次狀態機StateMachine
wifi 相關文件
framework
WifiManager
管理全部wifi操做,提供API調用,主要用於上層應用調用
WifiService
處理Wifi操做請求。通常都是在WifiManager中被調用
WifiStateMachine
處理wifi各個階段狀態所要處理的消息
WifiMonitor
監聽全部來自wpa_supplicant的事件,並傳遞給WifiStateMachine處理
WifiNative
native方法,發送消息給wpa_supplicant
jni層
android_net_wifi_Wifi.cpp
wpa_supplicant適配器層
wifi.c
wpa_supplicant層
wpa_supplicant.c
接下來分析wifi啓動、掃描、鏈接ap的流程。
1、 Wifi相關類建立
1.SystemServer::ServerThread::run---->new WifiService(...); 2.WifiService(...)---->new WifiStateMachine(...); 3.WifiStateMachine(...) ---->new WifiNative(...) ---->new WifiMonitor(...) ---->AsyncChannel::connectSync(...) ps: AsyncChannel::connectSync將WifiStateMachine和wifiApConfigStore經過AsyncChannel關聯起來。 4. SystemServer::ServerThread::run ServiceManager.addService(...);
over~~
-----------------------------------------------------------------
2、 wifi功能啓動
先貼出總體流程時序圖
1. 檢查系統屬性中的wifi狀態信息
SystemServer::ServerThread::run
--->WifiService::checkAndStartWifi (該方法只在開機時調用,用來檢查wifi是否須要開啓)
分析WifiService::checkAndStartWifi方法:
public void checkAndStartWifi() { mAirplaneModeOn.set(isAirplaneModeOn()); mPersistWifiState.set(getPersistedWifiState()); /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */ boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState(); Slog.i(TAG, "WifiService starting up with Wi-Fi " + (wifiEnabled ? "enabled" : "disabled")); // If we are already disabled (could be due to airplane mode), avoid changing persist // state here if (wifiEnabled) setWifiEnabled(wifiEnabled); mWifiWatchdogStateMachine = WifiWatchdogStateMachine. makeWifiWatchdogStateMachine(mContext); //之後分析 }
(1)isAirplaneModeOn()/getPersistedWifiState():都是獲取系統屬性進行判斷。
(2)shouldWifiBeEnabled():判斷mAirplaneModeOn/mPersistWifiState中的值,其實就是上述兩個方法得到的值。
(3)testAndClearWifiSavedState():獲取系統屬性中保存的wifi狀態的值,返回,以後清空狀態,置爲0。
另注意:如下分析都是基於條件:開機啓動時,wifi狀態爲on。
所以,接着會調用setWifiEnabled(true)方法,下面分析。
到此,檢查wifi系統屬性狀態的操做結束,over~~
2.setWifiEnabled(true)執行流程
2.1
該方法中主要執行如下語句:
if (FeatureQuery.FEATURE_CT_FMC_SUPPORT && WifiManager.fmcV2Support()) { mWifiStateMachine.fmcV2SetWifiEnabled(enable); } else { mWifiStateMachine.setWifiEnabled(enable); }
分析:
FeatureQuery.FEATURE_CT_FMC_SUPPORT/WifiManager.fmcV2Support()
(1)FeatureQuery.FEATURE_CT_FMC_SUPPORT
這個屬性值在build/buildplus/target/FeatureQuery.java裏能夠找到。
(2)WifiManager::fmcV2Support方法以下:
public static boolean fmcV2Support() { return (SystemProperties.getInt("ro.config.cwenable", 0) == 1) && (SystemProperties.getInt("ro.config.fmcv2support", 0) == 1); }
就是獲取兩個系統屬性,判斷是否支持FMC功能,有兩種方式能夠查看
(a)在out/target/product/msm8625/system/build.prop中能夠找到
(b)命令提示符下,adb shell,而後使用命令:getprop XX ,就能夠得到屬性值。XX表示系統屬性名。
總結:這兩個條件的做用就是判斷是否支持FMC功能(固定網絡與移動網絡融合)。
2.2
執行mWifiStateMachine.fmcV2SetWifiEnabled方法:
public void fmcV2SetWifiEnabled(boolean enable) { if (!enable) { ...... } else { setWifiEnabled(enable); } }
接着調用WifiStateMachine::setWifiEnabled(enable)方法: 發送兩個消息。
public void setWifiEnabled(boolean enable) { mLastEnableUid.set(Binder.getCallingUid()); if (enable) { /* Argument is the state that is entered prior to load */ sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0)); sendMessage(CMD_START_SUPPLICANT); } else { ...... } }
接收CMD_LOAD_DRIVER消息的是DriverUnloadedState狀態。
2.4 DriverUnloadedState狀態處理
public boolean processMessage(Message message) { if (DBG) log(getName() + message.toString() + "\n"); switch (message.what) { case CMD_LOAD_DRIVER: transitionTo(mDriverLoadingState); break; ...... }
在這裏CMD_LOAD_DRIVER消息被處理,切換到DriverLoadingState狀態。
2.5 DriverLoadingState 處理狀態
public void enter() { ...... final Message message = new Message(); message.copyFrom(getCurrentMessage()); new Thread(new Runnable() { public void run() { mWakeLock.acquire(); //enabling state switch(message.arg1) { case WIFI_STATE_ENABLING: setWifiState(WIFI_STATE_ENABLING); break; case WIFI_AP_STATE_ENABLING: setWifiApState(WIFI_AP_STATE_ENABLING); break; } if(mWifiNative.loadDriver()) { if (DBG) log("Driver load successful"); sendMessage(CMD_LOAD_DRIVER_SUCCESS); } ..... }
(1)在enter方法中經過message.copyFrom(getCurrentMessage()),從新得到了(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0)消息,而後開啓一個線程來處理。
(2)線程中首先判斷消息參數arg1,進入」case WIFI_STATE_ENABLING」,調用setWifiState方法。該方法主要是用來設置電池使用統計中的wifi信息。而後會發出一個WIFI_STATE_CHANGED_ACTION廣播。
(3)調用 WifiNative.loadDriver()方法加載wifi相關驅動,成功後發送CMD_LOAD_DRIVER_SUCCESS消息。該消息會在當前DriverLoadingState狀態的processMessage方法中被處理。
(4)處理CMD_LOAD_DRIVER_SUCCESS消息
case CMD_LOAD_DRIVER_SUCCESS: transitionTo(mDriverLoadedState); break; .....
狀態切換到DriverLoadedState。
2.6 DriverLoadedState狀態處理
處理WifiStateMachine::setWifiEnabled方法發出的CMD_START_SUPPLICANT消息(在此以前,該消息一直未被處理)。
case CMD_START_SUPPLICANT: ...... if(mWifiNative.startSupplicant(mP2pSupported)) { if (DBG) log("Supplicant start successful"); mWifiMonitor.startMonitoring(); transitionTo(mSupplicantStartingState); } ...... }
(1)啓動wpa_supplicant:
調用startSupplicant方法啓動。
(2)啓動WifiMonitor監聽
startMonitoring --->new MonitorThread().start() --->MonitorThread::run --->WifiMonitor::connectToSupplicant() --->WifiNative::connectToSupplicant() [最多嘗試5次] ---> mStateMachine.sendMessage(SUP_CONNECTION_EVENT)
最後成功鏈接上wpa_supplicant後,發出SUP_CONNECTION_EVENT消息。
(3)切換到SupplicantStartingState狀態
處理SUP_CONNECTION_EVENT消息:
case WifiMonitor.SUP_CONNECTION_EVENT: if (DBG) log("Supplicant connection established"); setWifiState(WIFI_STATE_ENABLED); ...... sendSupplicantConnectionChangedBroadcast(true); transitionTo(mDriverStartedState); break; ......
設置電池統計爲enabled,發出WIFI_STATE_CHANGED_ACTION廣播。這個廣播會被wifi應用和狀態欄接收處理;sendSupplicantConnectionChangedBroadcast方法發出廣播,只在測試代碼中被處理;最後切換到DriverStartedState狀態。
到此爲止,開機啓動wifi的工做就完成了,over~~
-----------------------------------------------------------------
3、打開wifi,自動掃描AP
1. WifiSettings類構造函數:
(1)定義了一個廣播;
(2)建立了一個Scanner對象(Scanner類是一個Handler子類,用來啓動掃描功能)
2. WifiSettings::onActivityCreated
---->new WifiEnabler(...) ---->WifiEnabler::resume() ---->resume方法中,爲Switch開關設置了checkedChange的監聽方法。
3. 初始化相關類對象的工做已完成,如今打開wifi。
首先點擊Switch開關,將觸發onCheckedChanged方法。在這裏,會先對飛行模式、wifi的狀態進行判斷。
---->WifiManger::setWifiEnabled ---->WifiService::setWifiEnabled ---->WifiStateMachine::setWifiEnabled ---->接下來的操做同」 開機wifi功能啓動」。直到開機wifi功能啓動完畢。
此時,WifiStateMachine::SupplicantStartingState::processMessage:
---->case WifiMonitor.SUP_CONNECTION_EVENT: setWifiState(WIFI_STATE_ENABLED); //wifi狀態爲enabled ......
該方法會發送一個WIFI_STATE_CHANGED_ACTION的粘性廣播。這個廣播會被WifiSettings類接收到。
4. WifiSettings處理WIFI_STATE_CHANGED_ACTION廣播
BroadcastReceiver::onReceive ---->handleEvent ---->updateWifiState //在該方法中,接着會調用Scanner::resume方法。 ---->Scanner::resume ---->Scanner::sendEmptyMessage(0) ---->Scanner::handleMessage 調用WifiManager::startScanActive方法進行掃描 ---->WifiManager::startScanActive ---->WifiService::startScan ---->WifiStateMachine::startScan //發出CMD_START_SCAN消息 該消息會被DriverstartedState狀態處理。 ---->WifiNative::scan
接着就調用到native層去了...這裏就不分析下去了,等後面總體分析...
分析完畢,over~~
-----------------------------------------------------------------
4、打開wifi,鏈接AP
分紅兩個部分分析:
1.wifi ap 提示框的建立
2.輸入密碼,鏈接ap
1. wifi ap 提示框的建立
初始條件:這裏分析安全性爲加密的ap。
1.1 點擊某個ap,調用流程:
---->WifiSettings::onPreferenceTreeClick ---->WifiSettings::showDialog(選擇的AP, false) 接着調用父類的showDialog方法 ---->SettingsPreferenceFragment::showDialog(WIFI_DIALOG_ID)
在SettingsPreferenceFragment類中,會建立一個SettingsDialogFragment對象,代碼以下:
protected void showDialog(int dialogId) { if (mDialogFragment != null) { Log.e(TAG, "Old dialog fragment not null!"); } //建立一個SettingsDialogFragment對象 mDialogFragment = new SettingsDialogFragment(this, dialogId); //(1) mDialogFragment.show(getActivity().getFragmentManager(), Integer.toString(dialogId)); //(2) }
(1) SettingsDialogFragment類繼承自DialogFragment類,會在onCreate後調用onCreateDialog方法。
---->SettingsDialogFragment(DialogCreatable fragment, int dialogId) ---->SettingsDialogFragment::onCreateDialog()
由於初始狀況下,savedInstanceState爲null,因此該方法直接回調構造函數中傳入的fragment參數的onCreateDialog方法,即WifiSettings::onCreateDialog。
---->WifiSettings::onCreateDialog
回到WifiSettings類:
在WifiSettings::onCreateDialog方法中,會建立一個WifiDialog類對象。
跳轉到WifiDialog類:
執行WifiDialog類的onCreate方法,會發現它建立了一個WifiConfigController類對象。
再看WifiConfigController類:
該類的構造函數主要是初始化了ap提示框的界面,固然還包括」添加網絡」的界面。
這樣,界面就建立了,須要顯示出來,這就是下一步的做用了。
(2)調用了DialogFragment::show方法,將提示框顯示出來。
至此,提示框分析完畢。
2. 輸入密碼,鏈接ap
(1)點擊ap提示框的「鏈接」按鈕,會調用WifiSettings::onClick方法:
public void onClick(DialogInterface dialogInterface, int button) { if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) { forget(); } else if (button == WifiDialog.BUTTON_SUBMIT) { if (FeatureQuery.FEATURE_CT_FMC_SUPPORT) { shouldShowErrorMsg = true; } submit(mDialog.getController()); } }
(2) 接着便調用submit方法,參數爲WifiConfigController類對象。
(3) submit方法中會調用WifiManager::connect方法進行鏈接。
over~~
-----------------------------------------------------------------
分析framework-->native-->wpa_supplicant幾個方法的調用流程
mWifiNative.isDriverLoaded() ---> android_net_wifi_Wifi.cpp::android_net_wifi_isDriverLoaded ---> wifi.c:: is_wifi_driver_loaded() --->查看系統屬性wlan.driver.status(ok爲已加載驅動,unloaded爲未加載)
mWifiNative.loadDriver() ---> android_net_wifi_Wifi.cpp::android_net_wifi_loadDriver ---> wifi.c:: wifi_load_driver() ---> ensure_wlan_driver_config_file_exists //首先判斷wifi的驅動配置文件是否加載 --->property_set //設置屬性 --->insmod //install modules 載入驅動模塊等
mWifiNative.startSupplicant(mP2pSupported) 參數爲mP2pSupported,便是否支持p2p ---> android_net_wifi_Wifi.cpp::android_net_wifi_startSupplicant ---> wifi.c::wifi_start_supplicant(p2pSupported) ---> ensure_config_file_exists //首先判斷wifi的配置文件是否加載 "/data/misc/wifi/wpa_supplicant.conf"; "/data/misc/wifi/p2p_supplicant.conf"; --->property_set("ctl.start", supplicant_name); // 這裏supplicant_name爲p2p_supplicant,因此就會啓動init.rc中名爲p2p_supplicant的服務了
ps:
property_set("ctl.start",xxx)
property_set("ctl.stop",xxx)
來使得android property service 去開啓或結束 xxx service.
由於init.qcom.rc中service p2p_supplicant中已經包含了wpa_supplicant啓動所需的語句及參數,因此後面會開始執行wpa_supplicant/main.c::main方法來初始化wpa_supplicant了。
wpa_supplicant初始化 見wpa_supplicant初始化
WifiMonitor::connectToSupplicant ---> mWifiNative.connectToSupplicant() ---> mWifiNative.connectToSupplicant(mInterface) //mInterface是建立WifiNative對象的時候傳遞進來的參數 ---> android_net_wifi_Wifi::android_net_wifi_connectToSupplicant ---> wifi.c:: wifi_connect_to_supplicant(ifname.c_str()) ---> 首先判斷文件IFACE_DIR = "/data/system/wpa_supplicant";是否存在, 存在:ifname="/data/system/wpa_supplicant/wlan0"; 不存在:ifname=wlan0 ---> wifi_connect_on_socket_path /* 首先,判斷系統屬性: * wlan.driver.status 是否爲ok * init.svc.p2p_supplicant 是否爲running * 而後,建立兩個socket(經過wpa_ctrl_open方法) * ctrl_conn:用於向wpa_supplicant發送命令並接收response * monitor_conn:它一直阻塞等待從wpa_supplicant過來的event * 最後調用wpa_ctrl_attach將monitor_conn信息註冊到wpa_supplicant */
wpa_ctrl_attach做用:因爲socket是數據報方式的,這一步是必須的,對於存在於wpa_supplicant的服務器端,它是全部客戶端共享的,因爲它須要主動向monitor_conn客戶端發送事件,因此它必須先記錄下該客戶端的詳細信息,wpa_supplicant就能夠將event發向該socket。
這樣,就經過socket,創建起native-->wpa_supplicant的鏈接了。
mWifiNative.waitForEvent() 該函數是有返回值的,返回值即爲wpa_supplicant傳遞過來的消息。 java層會經過jni方式調用android_net_wifi_waitForEvent(在線程MonitorThread中調用)方法,該方法會調用wifi_wait_for_event。在wifi_wait_for_event方法裏,會阻塞接收從wpa_supplicant模塊傳來的事件,一旦wpa_supplicant模塊發出事件,wifi_wait_for_event接收到後,會將包含事件的buf經過函數參數的方式回傳到java層,java收到事件後,再繼續調用wifi_wait_for_event函數進行阻塞等待接收,從而完成一個循環。 ---> mWifiNative::waitForEvent(mInterface) ---> android_net_wifi_Wifi.cpp::android_net_wifi_waitForEvent ---> wifi.c::wifi_wait_for_event(ifname.c_str(), buf, sizeof buf) ---> wifi_wait_on_socket ---> wifi_ctrl_recv ---> wpa_ctrl_recv ---> recv ps:從wpa_supplicant傳遞過來的值由recv函數接收,一直向上傳遞到buf參數中,最終返回return env->NewStringUTF(buf)給WifiMonitor。